From b428dd0a108b2572de14e3e90de6c31c69cc7ed0 Mon Sep 17 00:00:00 2001 From: philanthrope Date: Mon, 11 Dec 2023 15:13:32 -0500 Subject: [PATCH 1/8] Release/6.4.2 (#1611) * add timeout to websock, resolves hanging issue (#1609) * add timeout to websock, resolves hanging issue * add timeout set try/catch * add ability to turn off verbose logging for btcli cmds (#1608) * add ability to turn off verbose logging for btcli cmds * black * Add taostats explorer to map (#1607) * add taostats explorer to map and printed list of links for transfers * update test for explorer * add polkascan explorer endpoint * fix endpoint tests * table set take command This is intended as a fix for squash+merge issues that arise when merging master back into staging. Then PRs on github (not git) show the unsquashed commits when attempting to create a new release branch. * update changelog, version * don't log in process pool for stake command * Sudo/hyperparams pallet update (#1612) * Update hyperparams set extrinsic to use AdminUtils pallet * update metadata call --------- Co-authored-by: Ayden Brewer Co-authored-by: philanthrope * update changelog 1-sentence info * fix ful changelog diff * fix full changelog diff * fix changelog for 6.4.2 * fix readme typos * Hyperparams get update (#1614) * fixes `btcli sudo get` * black --------- Co-authored-by: Eugene-hu <85906264+Eugene-hu@users.noreply.github.com> Co-authored-by: Ayden Brewer --- CHANGELOG.md | 13 +++++- README.md | 17 +++---- VERSION | 2 +- bittensor/__init__.py | 15 ++++-- bittensor/chain_data.py | 6 +++ bittensor/commands/network.py | 1 - bittensor/commands/overview.py | 4 +- bittensor/commands/stake.py | 2 +- bittensor/extrinsics/network.py | 4 +- bittensor/extrinsics/transfer.py | 13 ++++-- bittensor/subtensor.py | 8 +++- bittensor/utils/__init__.py | 38 +++++++++------- tests/unit_tests/utils/test_utils.py | 68 ++++++++++++++++------------ 13 files changed, 121 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4992a86911..0f3fa2f34c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,23 @@ # Changelog +## 6.4.2 / 2023-12-07 + +## What's Changed +* Fix broken explorer links https://github.com/opentensor/bittensor/pull/1607 +* Fix spamming bittensor subtensor logging https://github.com/opentensor/bittensor/pull/1608 +* Fix hanging subtensor websocket https://github.com/opentensor/bittensor/pull/1609 +* Hparam update to palette: https://github.com/opentensor/bittensor/pull/1612 + +**Full Changelog**: https://github.com/opentensor/bittensor/compare/v6.4.1...v6.4.2 + + ## 6.4.1 / 2023-12-01 ## What's Changed * add helpful messages to signal coming changes in https://github.com/opentensor/bittensor/pull/1600/commits/86c0c3ccfcd91d0e3ff87f53bdc3e9c5e68661da * revert default subtensor network to finney in https://github.com/opentensor/bittensor/pull/1600/commits/8c69a3c15cd556384d0309e951f0a9b164dd36cb -**Full Changelog**: https://github.com/opentensor/bittensor/compare/v6.0.1...v6.4.1 +**Full Changelog**: https://github.com/opentensor/bittensor/compare/v6.4.0...v6.4.1 ## 6.4.0 / 2023-11-29 diff --git a/README.md b/README.md index 38ac11ab7c..fd631c35ee 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ positional arguments: lock_cost Return the lock cost to register a subnet. create Create a new bittensor subnetwork on this chain. register Register a wallet to a network. - register Register a wallet to a network using PoW. + pow_register Register a wallet to a network using PoW. hyperparameters View subnet hyperparameters. options: @@ -282,28 +282,28 @@ Axon: Serves Synapse protocols with custom blacklist, priority and verify functi ```python import bittensor -class MySyanpse( bittensor.Synapse ): +class MySynapse( bittensor.Synapse ): input: int = 1 output: int = None # Define a custom request forwarding function -def forward( synapse: MySyanpse ) -> MySyanpse: +def forward( synapse: MySynapse ) -> MySynapse: # Apply custom logic to synapse and return it synapse.output = 2 return synapse # Define a custom request verification function -def verify_my_synapse( synapse: MySyanpse ): +def verify_my_synapse( synapse: MySynapse ): # Apply custom verification logic to synapse # Optionally raise Exception # Define a custom request blacklist function -def blacklist_my_synapse( synapse: MySyanpse ) -> bool: +def blacklist_my_synapse( synapse: MySynapse ) -> bool: # Apply custom blacklist # return False ( if non blacklisted ) or True ( if blacklisted ) # Define a custom request priority function -def prioritize_my_synape( synapse: MySyanpse ) -> float: +def prioritize_my_synape( synapse: MySynapse ) -> float: # Apply custom priority return 1.0 @@ -321,6 +321,7 @@ my_axon.attach( Dendrite: Inheriting from PyTorch's Module class, represents the abstracted implementation of a network client module designed to send requests to those endpoints to receive inputs. + Example: ```python dendrite_obj = dendrite( wallet = bittensor.wallet() ) @@ -340,7 +341,7 @@ Use the `root` subcommand to access setting weights on the network across subnet ```bash btcli root weights --wallet.name --wallet.hotkey Enter netuids (e.g. 0, 1, 2 ...): -# Here enter your selected netuids to wet weights on +# Here enter your selected netuids to set weights on 1, 2 >Enter weights (e.g. 0.09, 0.09, 0.09 ...): @@ -377,4 +378,4 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I ## Acknowledgments -**learning-at-home/hivemind** +**learning-at-home/hivemind** \ No newline at end of file diff --git a/VERSION b/VERSION index 306894a15e..04757a5d3c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.4.1 \ No newline at end of file +6.4.2 \ No newline at end of file diff --git a/bittensor/__init__.py b/bittensor/__init__.py index 196f632ce4..3006a8de15 100644 --- a/bittensor/__init__.py +++ b/bittensor/__init__.py @@ -27,7 +27,7 @@ nest_asyncio.apply() # Bittensor code and protocol version. -__version__ = "6.4.1" +__version__ = "6.4.2" version_split = __version__.split(".") __version_as_int__ = ( (100 * int(version_split[0])) @@ -107,9 +107,16 @@ def debug(on: bool = True): # Block Explorers map network to explorer url ## Must all be polkadotjs explorer urls __network_explorer_map__ = { - "local": "https://explorer.finney.opentensor.ai/#/explorer", - "endpoint": "https://explorer.finney.opentensor.ai/#/explorer", - "finney": "https://explorer.finney.opentensor.ai/#/explorer", + "opentensor": { + "local": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer", + "endpoint": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer", + "finney": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer", + }, + "taostats": { + "local": "https://x.taostats.io", + "endpoint": "https://x.taostats.io", + "finney": "https://x.taostats.io", + }, } # --- Type Registry --- diff --git a/bittensor/chain_data.py b/bittensor/chain_data.py index 3f44a66a01..eeb946e20f 100644 --- a/bittensor/chain_data.py +++ b/bittensor/chain_data.py @@ -174,6 +174,8 @@ ["max_burn", "Compact"], ["bonds_moving_avg", "Compact"], ["max_regs_per_block", "Compact"], + ["serving_rate_limit", "Compact"], + ["max_validators", "Compact"], ], }, } @@ -963,6 +965,8 @@ class SubnetHyperparameters: max_burn: int bonds_moving_avg: int max_regs_per_block: int + serving_rate_limit: int + max_validators: int @classmethod def from_vec_u8(cls, vec_u8: List[int]) -> Optional["SubnetHyperparameters"]: @@ -1013,6 +1017,8 @@ def fix_decoded_values(cls, decoded: Dict) -> "SubnetHyperparameters": max_burn=decoded["max_burn"], bonds_moving_avg=decoded["bonds_moving_avg"], max_regs_per_block=decoded["max_regs_per_block"], + max_validators=decoded["max_validators"], + serving_rate_limit=decoded["serving_rate_limit"], ) def to_parameter_dict(self) -> "torch.nn.ParameterDict": diff --git a/bittensor/commands/network.py b/bittensor/commands/network.py index 32ae141cb6..6c0eefff39 100644 --- a/bittensor/commands/network.py +++ b/bittensor/commands/network.py @@ -249,7 +249,6 @@ def add_args(parser: argparse.ArgumentParser): "immunity_period": "sudo_set_immunity_period", "min_allowed_weights": "sudo_set_min_allowed_weights", "activity_cutoff": "sudo_set_activity_cutoff", - "max_validators": "sudo_set_max_allowed_validators", } diff --git a/bittensor/commands/overview.py b/bittensor/commands/overview.py index 39fc465b07..c8317b572f 100644 --- a/bittensor/commands/overview.py +++ b/bittensor/commands/overview.py @@ -558,7 +558,7 @@ def _get_neurons_for_netuid( result: List["bittensor.NeuronInfoLite"] = [] try: - subtensor = bittensor.subtensor(config=subtensor_config) + subtensor = bittensor.subtensor(config=subtensor_config, log_verbose=False) all_neurons: List["bittensor.NeuronInfoLite"] = subtensor.neurons_lite( netuid=netuid @@ -587,7 +587,7 @@ def _get_de_registered_stake_for_coldkey_wallet( result: List[Tuple[str, "bittensor.Balance"]] = [] try: - subtensor = bittensor.subtensor(config=subtensor_config) + subtensor = bittensor.subtensor(config=subtensor_config, log_verbose=False) # Pull all stake for our coldkey all_stake_info_for_coldkey = subtensor.get_stake_info_for_coldkey( diff --git a/bittensor/commands/stake.py b/bittensor/commands/stake.py index 51f54afe97..400d70404c 100644 --- a/bittensor/commands/stake.py +++ b/bittensor/commands/stake.py @@ -375,7 +375,7 @@ def get_stake_accounts(wallet) -> Dict[str, Dict[str, Union[str, Balance]]]: Returns: A dictionary mapping SS58 addresses to their respective stake account details. """ - subtensor = bittensor.subtensor(config=cli.config) + subtensor = bittensor.subtensor(config=cli.config, log_verbose=False) wallet_stake_accounts = {} diff --git a/bittensor/extrinsics/network.py b/bittensor/extrinsics/network.py index 04447e9f14..d148005e31 100644 --- a/bittensor/extrinsics/network.py +++ b/bittensor/extrinsics/network.py @@ -159,7 +159,7 @@ def set_hyperparameter_extrinsic( ): with subtensor.substrate as substrate: extrinsic_params = substrate.get_metadata_call_function( - "SubtensorModule", extrinsic + "AdminUtils", extrinsic ) value_argument = extrinsic_params["fields"][ len(extrinsic_params["fields"]) - 1 @@ -167,7 +167,7 @@ def set_hyperparameter_extrinsic( # create extrinsic call call = substrate.compose_call( - call_module="SubtensorModule", + call_module="AdminUtils", call_function=extrinsic, call_params={"netuid": netuid, str(value_argument["name"]): value}, ) diff --git a/bittensor/extrinsics/transfer.py b/bittensor/extrinsics/transfer.py index 86fcce70a5..915cf8730a 100644 --- a/bittensor/extrinsics/transfer.py +++ b/bittensor/extrinsics/transfer.py @@ -129,12 +129,19 @@ def transfer_extrinsic( "[green]Block Hash: {}[/green]".format(block_hash) ) - explorer_url = bittensor.utils.get_explorer_url_for_network( + explorer_urls = bittensor.utils.get_explorer_url_for_network( subtensor.network, block_hash, bittensor.__network_explorer_map__ ) - if explorer_url is not None: + if explorer_urls != {}: bittensor.__console__.print( - "[green]Explorer Link: {}[/green]".format(explorer_url) + "[green]Opentensor Explorer Link: {}[/green]".format( + explorer_urls.get("opentensor") + ) + ) + bittensor.__console__.print( + "[green]Taostats Explorer Link: {}[/green]".format( + explorer_urls.get("taostats") + ) ) else: bittensor.__console__.print( diff --git a/bittensor/subtensor.py b/bittensor/subtensor.py index 52ae1b482c..dd08c75953 100644 --- a/bittensor/subtensor.py +++ b/bittensor/subtensor.py @@ -298,6 +298,7 @@ def __init__( network: str = None, config: "bittensor.config" = None, _mock: bool = False, + log_verbose: bool = True, ) -> None: """ Initializes a Subtensor interface for interacting with the Bittensor blockchain. @@ -333,7 +334,7 @@ def __init__( if ( self.network == "finney" or self.chain_endpoint == bittensor.__finney_entrypoint__ - ): + ) and log_verbose: bittensor.logging.info( f"You are connecting to {self.network} network with endpoint {self.chain_endpoint}." ) @@ -375,6 +376,11 @@ def __init__( exit(1) # TODO (edu/phil): Advise to run local subtensor and point to dev docs. + try: + self.substrate.websocket.settimeout(600) + except: + bittensor.logging.warning("Could not set websocket timeout.") + bittensor.logging.info( f"Connected to {self.network} network and {self.chain_endpoint}." ) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index aa9b5e854b..2b3aba4c97 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -123,8 +123,8 @@ def strtobool(val: str) -> Union[bool, Literal["==SUPRESS=="]]: def get_explorer_root_url_by_network_from_map( - network: str, network_map: Dict[str, str] -) -> Optional[str]: + network: str, network_map: Dict[str, Dict[str, str]] +) -> Optional[Dict[str, str]]: r""" Returns the explorer root url for the given network name from the given network map. @@ -136,42 +136,48 @@ def get_explorer_root_url_by_network_from_map( The explorer url for the given network. Or None if the network is not in the network map. """ - explorer_url: Optional[str] = None - if network in network_map: - explorer_url = network_map[network] + explorer_urls: Optional[Dict[str, str]] = {} + for entity_nm, entity_network_map in network_map.items(): + if network in entity_network_map: + explorer_urls[entity_nm] = entity_network_map[network] - return explorer_url + return explorer_urls def get_explorer_url_for_network( network: str, block_hash: str, network_map: Dict[str, str] -) -> Optional[str]: +) -> Optional[List[str]]: r""" Returns the explorer url for the given block hash and network. Args: network(str): The network to get the explorer url for. block_hash(str): The block hash to get the explorer url for. - network_map(Dict[str, str]): The network map to get the explorer url from. + network_map(Dict[str, Dict[str, str]]): The network maps to get the explorer urls from. Returns: The explorer url for the given block hash and network. Or None if the network is not known. """ - explorer_url: Optional[str] = None + explorer_urls: Optional[Dict[str, str]] = {} # Will be None if the network is not known. i.e. not in network_map - explorer_root_url: Optional[str] = get_explorer_root_url_by_network_from_map( - network, network_map - ) + explorer_root_urls: Optional[ + Dict[str, str] + ] = get_explorer_root_url_by_network_from_map(network, network_map) - if explorer_root_url is not None: + if explorer_root_urls != {}: # We are on a known network. - explorer_url = "{root_url}/query/{block_hash}".format( - root_url=explorer_root_url, block_hash=block_hash + explorer_opentensor_url = "{root_url}/query/{block_hash}".format( + root_url=explorer_root_urls.get("opentensor"), block_hash=block_hash + ) + explorer_taostats_url = "{root_url}/search?query={block_hash}".format( + root_url=explorer_root_urls.get("taostats"), block_hash=block_hash ) + explorer_urls["opentensor"] = explorer_opentensor_url + explorer_urls["taostats"] = explorer_taostats_url - return explorer_url + return explorer_urls def ss58_address_to_bytes(ss58_address: str) -> bytes: diff --git a/tests/unit_tests/utils/test_utils.py b/tests/unit_tests/utils/test_utils.py index c3d214ff07..3309bc35b0 100644 --- a/tests/unit_tests/utils/test_utils.py +++ b/tests/unit_tests/utils/test_utils.py @@ -700,63 +700,71 @@ class MockException(Exception): @ddt class TestExplorerURL(unittest.TestCase): - network_map: Dict[str, str] = { - "nakamoto": "https://polkadot.js.org/apps/?rpc=wss://archivelb.nakamoto.opentensor.ai:9943#/explorer", - "example": "https://polkadot.js.org/apps/?rpc=wss://example.example.com#/explorer", - "nobunaga": "https://polkadot.js.org/apps/?rpc=wss://nobunaga.bittensor.com:9943#/explorer", - # "bad": None # no explorer for this network - } - @data( ( - "nobunaga", - "https://polkadot.js.org/apps/?rpc=wss://nobunaga.bittensor.com:9943#/explorer", + "local", + { + "opentensor": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer", + "taostats": "https://x.taostats.io", + }, ), ( - "nakamoto", - "https://polkadot.js.org/apps/?rpc=wss://archivelb.nakamoto.opentensor.ai:9943#/explorer", + "endpoint", + { + "opentensor": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer", + "taostats": "https://x.taostats.io", + }, ), ( - "example", - "https://polkadot.js.org/apps/?rpc=wss://example.example.com#/explorer", + "finney", + { + "opentensor": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer", + "taostats": "https://x.taostats.io", + }, ), - ("bad", None), - ("", None), - ("networknamewithoutexplorer", None), + ("bad", {}), + ("", {}), + ("unknown", {}), ) @unpack def test_get_explorer_root_url_by_network_from_map( - self, network: str, expected: str - ) -> str: + self, network: str, expected: dict + ) -> None: self.assertEqual( bittensor.utils.get_explorer_root_url_by_network_from_map( - network, self.network_map + network, bittensor.__network_explorer_map__ ), expected, ) @data( ( - "nobunaga", + "local", "0x123", - "https://polkadot.js.org/apps/?rpc=wss://nobunaga.bittensor.com:9943#/explorer/query/0x123", + { + "opentensor": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer/query/0x123", + "taostats": "https://x.taostats.io/search?query=0x123", + }, ), ( - "example", - "0x123", - "https://polkadot.js.org/apps/?rpc=wss://example.example.com#/explorer/query/0x123", + "endpoint", + "0x456", + { + "opentensor": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fentrypoint-finney.opentensor.ai%3A443#/explorer/query/0x456", + "taostats": "https://x.taostats.io/search?query=0x456", + }, ), - ("bad", "0x123", None), - ("", "0x123", None), - ("networknamewithoutexplorer", "0x123", None), + ("bad", "0x789", {}), + ("", "0xabc", {}), + ("unknown", "0xdef", {}), ) @unpack def test_get_explorer_url_for_network_by_network_and_block_hash( - self, network: str, block_hash: str, expected: str - ) -> str: + self, network: str, block_hash: str, expected: dict + ) -> None: self.assertEqual( bittensor.utils.get_explorer_url_for_network( - network, block_hash, self.network_map + network, block_hash, bittensor.__network_explorer_map__ ), expected, ) From 7c1464354de787792e1cb109eab269fdc2858c74 Mon Sep 17 00:00:00 2001 From: Ayden Brewer Date: Tue, 12 Dec 2023 14:58:27 -0800 Subject: [PATCH 2/8] Add an api for metadata commitments to extrinsics.serving --- bittensor/errors.py | 4 ++++ bittensor/extrinsics/serving.py | 40 ++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/bittensor/errors.py b/bittensor/errors.py index 36dac7c588..f49c89960d 100644 --- a/bittensor/errors.py +++ b/bittensor/errors.py @@ -80,3 +80,7 @@ class KeyFileError(Exception): """Error thrown when the keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid.""" pass + +class MetadataError(ChainTransactionError): + r"""Error raised when metadata commitment transaction fails.""" + pass diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index 4bdfde7f76..a687a24d8f 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -20,7 +20,7 @@ from dataclasses import asdict import bittensor.utils.networking as net from rich.prompt import Confirm - +from ..errors import MetadataError def serve_extrinsic( subtensor: "bittensor.subtensor", @@ -203,3 +203,41 @@ def serve_axon_extrinsic( prompt=prompt, ) return serve_success + +def publish_metadata( + subtensor: "bittensor.subtensor", + wallet: "bittensor.wallet", + netuid: int, + type: str, + hash: str, + wait_for_inclusion: bool = False, + wait_for_finalization: bool = True, +) -> bool: + wallet.hotkey + + with subtensor.substrate as substrate: + call = substrate.compose_call( + call_module="Commitments", + call_function="set_commitment", + call_params={ + "netuid": netuid, + "info": {"fields": [[{f"{type}": hash}]]} + } + ) + + extrinsic = substrate.create_signed_extrinsic( + call=call, keypair=wallet.hotkey + ) + response = substrate.submit_extrinsic( + extrinsic, + wait_for_inclusion=wait_for_inclusion, + wait_for_finalization=wait_for_finalization, + ) + # We only wait here if we expect finalization. + if not wait_for_finalization and not wait_for_inclusion: + return True + response.process_events() + if response.is_success: + return True + else: + raise MetadataError(response.error_message) \ No newline at end of file From db0a15405c6d7c45fabbfd2bdcb9f270a5e62ca1 Mon Sep 17 00:00:00 2001 From: Ayden Brewer Date: Tue, 12 Dec 2023 15:00:07 -0800 Subject: [PATCH 3/8] Change extrinsics.serving.publish_metadata argument hash to data --- bittensor/extrinsics/serving.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index a687a24d8f..81d7994353 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -209,7 +209,7 @@ def publish_metadata( wallet: "bittensor.wallet", netuid: int, type: str, - hash: str, + data: str, wait_for_inclusion: bool = False, wait_for_finalization: bool = True, ) -> bool: @@ -221,7 +221,7 @@ def publish_metadata( call_function="set_commitment", call_params={ "netuid": netuid, - "info": {"fields": [[{f"{type}": hash}]]} + "info": {"fields": [[{f"{type}": data}]]} } ) From 1398ab92f882c491bc22dbcb29cb8a74b2152c7d Mon Sep 17 00:00:00 2001 From: ifrit98 Date: Wed, 13 Dec 2023 00:14:52 +0000 Subject: [PATCH 4/8] add docstring to publish-metadata --- bittensor/errors.py | 1 + bittensor/extrinsics/serving.py | 46 +++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/bittensor/errors.py b/bittensor/errors.py index f49c89960d..5be2090441 100644 --- a/bittensor/errors.py +++ b/bittensor/errors.py @@ -81,6 +81,7 @@ class KeyFileError(Exception): pass + class MetadataError(ChainTransactionError): r"""Error raised when metadata commitment transaction fails.""" pass diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index 81d7994353..ee7e9e8e60 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -22,6 +22,7 @@ from rich.prompt import Confirm from ..errors import MetadataError + def serve_extrinsic( subtensor: "bittensor.subtensor", wallet: "bittensor.wallet", @@ -204,6 +205,7 @@ def serve_axon_extrinsic( ) return serve_success + def publish_metadata( subtensor: "bittensor.subtensor", wallet: "bittensor.wallet", @@ -213,21 +215,49 @@ def publish_metadata( wait_for_inclusion: bool = False, wait_for_finalization: bool = True, ) -> bool: + """ + Publishes metadata on the bittensor network using the specified wallet and network identifier. + + Args: + subtensor (bittensor.subtensor): + The subtensor instance representing the bittensor blockchain connection. + wallet (bittensor.wallet): + The wallet object used for authentication in the transaction. + netuid (int): + Network UID on which the metadata is to be published. + type (str): + The data type of the information being submitted. It should be one of the following: + 'Sha256', 'Blake256', 'Keccak256', or 'Raw0-128'. This specifies the format or + hashing algorithm used for the data. + data (str): + The actual metadata content to be published. This should be formatted or hashed + according to the 'type' specified. + wait_for_inclusion (bool, optional): + If True, the function will wait for the extrinsic to be included in a block before returning. + Defaults to False. + wait_for_finalization (bool, optional): + If True, the function will wait for the extrinsic to be finalized on the chain before returning. + Defaults to True. + + Returns: + bool: + True if the metadata was successfully published (and finalized if specified). False otherwise. + + Raises: + MetadataError: + If there is an error in submitting the extrinsic or if the response from the blockchain indicates failure. + """ + wallet.hotkey with subtensor.substrate as substrate: call = substrate.compose_call( call_module="Commitments", call_function="set_commitment", - call_params={ - "netuid": netuid, - "info": {"fields": [[{f"{type}": data}]]} - } + call_params={"netuid": netuid, "info": {"fields": [[{f"{type}": data}]]}}, ) - extrinsic = substrate.create_signed_extrinsic( - call=call, keypair=wallet.hotkey - ) + extrinsic = substrate.create_signed_extrinsic(call=call, keypair=wallet.hotkey) response = substrate.submit_extrinsic( extrinsic, wait_for_inclusion=wait_for_inclusion, @@ -240,4 +270,4 @@ def publish_metadata( if response.is_success: return True else: - raise MetadataError(response.error_message) \ No newline at end of file + raise MetadataError(response.error_message) From 4fd1081660d74c15f9e922112d4fa7e2269650e9 Mon Sep 17 00:00:00 2001 From: Ayden Brewer Date: Thu, 14 Dec 2023 11:31:19 -0800 Subject: [PATCH 5/8] Add QoL function to get commitment data for netuid,uid --- bittensor/extrinsics/serving.py | 17 +++++++++++++++++ bittensor/subtensor.py | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index ee7e9e8e60..3bc5fe85ea 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -271,3 +271,20 @@ def publish_metadata( return True else: raise MetadataError(response.error_message) + +from retry import retry + +def get_metadata(self, netuid: int, hotkey: str, block) -> str: + @retry(delay=2, tries=3, backoff=2, max_delay=4) + def make_substrate_call_with_retry(): + with self.substrate as substrate: + return substrate.query( + module="Commitments", + storage_function="CommitmentOf", + params=[netuid, hotkey], + block_hash=None + if block == None + else substrate.get_block_hash(block), + ) + + return make_substrate_call_with_retry() \ No newline at end of file diff --git a/bittensor/subtensor.py b/bittensor/subtensor.py index dd08c75953..475d885adf 100644 --- a/bittensor/subtensor.py +++ b/bittensor/subtensor.py @@ -52,7 +52,7 @@ ) from .extrinsics.staking import add_stake_extrinsic, add_stake_multiple_extrinsic from .extrinsics.unstaking import unstake_extrinsic, unstake_multiple_extrinsic -from .extrinsics.serving import serve_extrinsic, serve_axon_extrinsic +from .extrinsics.serving import serve_extrinsic, serve_axon_extrinsic, publish_metadata, get_metadata from .extrinsics.registration import ( register_extrinsic, burned_register_extrinsic, @@ -2111,6 +2111,22 @@ def make_substrate_call_with_retry(): return make_substrate_call_with_retry() + ''' Make some commitment on-chain about arbitary data ''' + + def commit( + self, + wallet, + netuid: int, + data: str + ): + publish_metadata(self, wallet, netuid, f"Raw{len(data)}", data.encode()) + + def get_commitment(self, netuid: int, uid: int, block) -> str: + metagraph = self.metagraph(netuid) + hotkey = metagraph.hotkeys[uid] + + return get_metadata(self, netuid, hotkey, block) + ######################## #### Standard Calls #### ######################## From da1ddd5ef638a722b6c3fcdde5788d3ff134579d Mon Sep 17 00:00:00 2001 From: Ayden Brewer Date: Thu, 14 Dec 2023 11:40:08 -0800 Subject: [PATCH 6/8] Return storage struct directly instead of scale object --- bittensor/extrinsics/serving.py | 7 ++++--- bittensor/subtensor.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index 3bc5fe85ea..a5dc1893b3 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -273,8 +273,9 @@ def publish_metadata( raise MetadataError(response.error_message) from retry import retry +from typing import Optional -def get_metadata(self, netuid: int, hotkey: str, block) -> str: +def get_metadata(self, netuid: int, hotkey: str, block: Optional[int] = None) -> str: @retry(delay=2, tries=3, backoff=2, max_delay=4) def make_substrate_call_with_retry(): with self.substrate as substrate: @@ -286,5 +287,5 @@ def make_substrate_call_with_retry(): if block == None else substrate.get_block_hash(block), ) - - return make_substrate_call_with_retry() \ No newline at end of file + commit_data = make_substrate_call_with_retry() + return commit_data.value \ No newline at end of file diff --git a/bittensor/subtensor.py b/bittensor/subtensor.py index 475d885adf..abecb707d1 100644 --- a/bittensor/subtensor.py +++ b/bittensor/subtensor.py @@ -2121,7 +2121,7 @@ def commit( ): publish_metadata(self, wallet, netuid, f"Raw{len(data)}", data.encode()) - def get_commitment(self, netuid: int, uid: int, block) -> str: + def get_commitment(self, netuid: int, uid: int, block: Optional[int] = None) -> str: metagraph = self.metagraph(netuid) hotkey = metagraph.hotkeys[uid] From 7d0ff37b8d9e91fc55b374c35c98a683ffd9d71c Mon Sep 17 00:00:00 2001 From: ifrit98 Date: Thu, 14 Dec 2023 19:45:44 +0000 Subject: [PATCH 7/8] add maxlen str --- bittensor/extrinsics/serving.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index a5dc1893b3..086ba3dda2 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -231,7 +231,7 @@ def publish_metadata( hashing algorithm used for the data. data (str): The actual metadata content to be published. This should be formatted or hashed - according to the 'type' specified. + according to the 'type' specified. (Note: max str length of 128 bytes) wait_for_inclusion (bool, optional): If True, the function will wait for the extrinsic to be included in a block before returning. Defaults to False. From c186406fea1f884195cb6248324c189ec220a352 Mon Sep 17 00:00:00 2001 From: ifrit98 Date: Thu, 14 Dec 2023 19:50:37 +0000 Subject: [PATCH 8/8] blacks --- bittensor/extrinsics/serving.py | 11 ++++++----- bittensor/subtensor.py | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/bittensor/extrinsics/serving.py b/bittensor/extrinsics/serving.py index 086ba3dda2..11eb8e24e4 100644 --- a/bittensor/extrinsics/serving.py +++ b/bittensor/extrinsics/serving.py @@ -271,10 +271,12 @@ def publish_metadata( return True else: raise MetadataError(response.error_message) - + + from retry import retry from typing import Optional + def get_metadata(self, netuid: int, hotkey: str, block: Optional[int] = None) -> str: @retry(delay=2, tries=3, backoff=2, max_delay=4) def make_substrate_call_with_retry(): @@ -283,9 +285,8 @@ def make_substrate_call_with_retry(): module="Commitments", storage_function="CommitmentOf", params=[netuid, hotkey], - block_hash=None - if block == None - else substrate.get_block_hash(block), + block_hash=None if block == None else substrate.get_block_hash(block), ) + commit_data = make_substrate_call_with_retry() - return commit_data.value \ No newline at end of file + return commit_data.value diff --git a/bittensor/subtensor.py b/bittensor/subtensor.py index 3f2ee1ee10..bdf9622f07 100644 --- a/bittensor/subtensor.py +++ b/bittensor/subtensor.py @@ -52,7 +52,12 @@ ) from .extrinsics.staking import add_stake_extrinsic, add_stake_multiple_extrinsic from .extrinsics.unstaking import unstake_extrinsic, unstake_multiple_extrinsic -from .extrinsics.serving import serve_extrinsic, serve_axon_extrinsic, publish_metadata, get_metadata +from .extrinsics.serving import ( + serve_extrinsic, + serve_axon_extrinsic, + publish_metadata, + get_metadata, +) from .extrinsics.registration import ( register_extrinsic, burned_register_extrinsic, @@ -2143,14 +2148,9 @@ def make_substrate_call_with_retry(): return make_substrate_call_with_retry() - ''' Make some commitment on-chain about arbitary data ''' + """ Make some commitment on-chain about arbitary data """ - def commit( - self, - wallet, - netuid: int, - data: str - ): + def commit(self, wallet, netuid: int, data: str): publish_metadata(self, wallet, netuid, f"Raw{len(data)}", data.encode()) def get_commitment(self, netuid: int, uid: int, block: Optional[int] = None) -> str: