Source code for bittensor.extrinsics.network

# The MIT License (MIT)
# Copyright © 2021 Yuma Rao
# Copyright © 2023 Opentensor Foundation

# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
# the Software.

# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

import time

import substrateinterface
from rich.prompt import Confirm

import bittensor
from bittensor.utils import format_error_message
from ..commands.network import HYPERPARAMS


[docs] def _find_event_attributes_in_extrinsic_receipt( response: "substrateinterface.base.ExtrinsicReceipt", event_name: str ) -> list: """ Searches for the attributes of a specified event within an extrinsic receipt. Args: response (substrateinterface.base.ExtrinsicReceipt): The receipt of the extrinsic to be searched. event_name (str): The name of the event to search for. Returns: list: A list of attributes for the specified event. Returns [-1] if the event is not found. """ for event in response.triggered_events: # Access the event details event_details = event.value["event"] # Check if the event_id is 'NetworkAdded' if event_details["event_id"] == event_name: # Once found, you can access the attributes of the event_name return event_details["attributes"] return [-1]
[docs] def register_subnetwork_extrinsic( subtensor: "bittensor.subtensor", wallet: "bittensor.wallet", wait_for_inclusion: bool = False, wait_for_finalization: bool = True, prompt: bool = False, ) -> bool: r"""Registers a new subnetwork. Args: wallet (bittensor.wallet): bittensor wallet object. wait_for_inclusion (bool): If set, waits for the extrinsic to enter a block before returning ``true``, or returns ``false`` if the extrinsic fails to enter the block within the timeout. wait_for_finalization (bool): If set, waits for the extrinsic to be finalized on the chain before returning ``true``, or returns ``false`` if the extrinsic fails to be finalized within the timeout. prompt (bool): If true, the call waits for confirmation from the user before proceeding. Returns: success (bool): Flag is ``true`` if extrinsic was finalized or included in the block. If we did not wait for finalization / inclusion, the response is ``true``. """ your_balance = subtensor.get_balance(wallet.coldkeypub.ss58_address) burn_cost = bittensor.utils.balance.Balance(subtensor.get_subnet_burn_cost()) if burn_cost > your_balance: bittensor.__console__.print( f"Your balance of: [green]{your_balance}[/green] is not enough to pay the subnet lock cost of: [green]{burn_cost}[/green]" ) return False if prompt: bittensor.__console__.print(f"Your balance is: [green]{your_balance}[/green]") if not Confirm.ask( f"Do you want to register a subnet for [green]{ burn_cost }[/green]?" ): return False try: wallet.coldkey # unlock coldkey except bittensor.KeyFileError: bittensor.__console__.print( ":cross_mark: [red]Keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid[/red]:[bold white]\n [/bold white]" ) return False with bittensor.__console__.status(":satellite: Registering subnet..."): with subtensor.substrate as substrate: # create extrinsic call call = substrate.compose_call( call_module="SubtensorModule", call_function="register_network", call_params={"immunity_period": 0, "reg_allowed": True}, ) extrinsic = substrate.create_signed_extrinsic( call=call, keypair=wallet.coldkey ) 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 # process if registration successful response.process_events() if not response.is_success: bittensor.__console__.print( f":cross_mark: [red]Failed[/red]: {format_error_message(response.error_message)}" ) time.sleep(0.5) # Successful registration, final check for membership else: attributes = _find_event_attributes_in_extrinsic_receipt( response, "NetworkAdded" ) bittensor.__console__.print( f":white_heavy_check_mark: [green]Registered subnetwork with netuid: {attributes[0]}[/green]" ) return True
[docs] def set_hyperparameter_extrinsic( subtensor: "bittensor.subtensor", wallet: "bittensor.wallet", netuid: int, parameter: str, value, wait_for_inclusion: bool = False, wait_for_finalization: bool = True, prompt: bool = False, ) -> bool: r"""Sets a hyperparameter for a specific subnetwork. Args: wallet (bittensor.wallet): bittensor wallet object. netuid (int): Subnetwork ``uid``. parameter (str): Hyperparameter name. value (any): New hyperparameter value. wait_for_inclusion (bool): If set, waits for the extrinsic to enter a block before returning ``true``, or returns ``false`` if the extrinsic fails to enter the block within the timeout. wait_for_finalization (bool): If set, waits for the extrinsic to be finalized on the chain before returning ``true``, or returns ``false`` if the extrinsic fails to be finalized within the timeout. prompt (bool): If ``true``, the call waits for confirmation from the user before proceeding. Returns: success (bool): Flag is ``true`` if extrinsic was finalized or included in the block. If we did not wait for finalization / inclusion, the response is ``true``. """ if subtensor.get_subnet_owner(netuid) != wallet.coldkeypub.ss58_address: bittensor.__console__.print( ":cross_mark: [red]This wallet doesn't own the specified subnet.[/red]" ) return False wallet.coldkey # unlock coldkey extrinsic = HYPERPARAMS.get(parameter) if extrinsic is None: bittensor.__console__.print( ":cross_mark: [red]Invalid hyperparameter specified.[/red]" ) return False with bittensor.__console__.status( f":satellite: Setting hyperparameter {parameter} to {value} on subnet: {netuid} ..." ): with subtensor.substrate as substrate: extrinsic_params = substrate.get_metadata_call_function( "AdminUtils", extrinsic ) call_params = {"netuid": netuid} # if input value is a list, iterate through the list and assign values if isinstance(value, list): # Create an iterator for the list of values value_iterator = iter(value) # Iterate over all value arguments and add them to the call_params dictionary for value_argument in extrinsic_params["fields"]: if "netuid" not in str(value_argument["name"]): # Assign the next value from the iterator try: call_params[str(value_argument["name"])] = next( value_iterator ) except StopIteration: raise ValueError( "Not enough values provided in the list for all parameters" ) else: value_argument = extrinsic_params["fields"][ len(extrinsic_params["fields"]) - 1 ] call_params[str(value_argument["name"])] = value # create extrinsic call call = substrate.compose_call( call_module="AdminUtils", call_function=extrinsic, call_params=call_params, ) extrinsic = substrate.create_signed_extrinsic( call=call, keypair=wallet.coldkey ) 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 # process if registration successful response.process_events() if not response.is_success: bittensor.__console__.print( f":cross_mark: [red]Failed[/red]: {format_error_message(response.error_message)}" ) time.sleep(0.5) # Successful registration, final check for membership else: bittensor.__console__.print( f":white_heavy_check_mark: [green]Hyper parameter {parameter} changed to {value}[/green]" ) return True