Source code for bittensor.core.chain_data.utils

"""Chain data helper functions and data."""

from enum import Enum
from typing import Optional, Union

from scalecodec.base import RuntimeConfiguration, ScaleBytes
from scalecodec.type_registry import load_type_registry_preset
from scalecodec.utils.ss58 import ss58_encode

from bittensor.core.settings import SS58_FORMAT
from bittensor.utils.balance import Balance


[docs] class ChainDataType(Enum): NeuronInfo = 1 SubnetInfo = 2 DelegateInfo = 3 NeuronInfoLite = 4 DelegatedInfo = 5 StakeInfo = 6 IPInfo = 7 SubnetHyperparameters = 8 ScheduledColdkeySwapInfo = 9 AccountId = 10
[docs] def from_scale_encoding( input_: Union[list[int], bytes, "ScaleBytes"], type_name: "ChainDataType", is_vec: bool = False, is_option: bool = False, ) -> Optional[dict]: """ Decodes input_ data from SCALE encoding based on the specified type name and modifiers. Args: input_ (Union[List[int], bytes, ScaleBytes]): The input_ data to decode. type_name (ChainDataType): The type of data being decoded. is_vec (bool): Whether the data is a vector of the specified type. Default is ``False``. is_option (bool): Whether the data is an optional value of the specified type. Default is ``False``. Returns: Optional[dict]: The decoded data as a dictionary, or ``None`` if the decoding fails. """ type_string = type_name.name if type_name == ChainDataType.DelegatedInfo: # DelegatedInfo is a tuple of (DelegateInfo, Compact<u64>) type_string = f"({ChainDataType.DelegateInfo.name}, Compact<u64>)" if is_option: type_string = f"Option<{type_string}>" if is_vec: type_string = f"Vec<{type_string}>" return from_scale_encoding_using_type_string(input_, type_string)
[docs] def from_scale_encoding_using_type_string( input_: Union[list[int], bytes, ScaleBytes], type_string: str ) -> Optional[dict]: """ Decodes SCALE encoded data to a dictionary based on the provided type string. Args: input_ (Union[List[int], bytes, ScaleBytes]): The SCALE encoded input data. type_string (str): The type string defining the structure of the data. Returns: Optional[dict]: The decoded data as a dictionary, or ``None`` if the decoding fails. Raises: TypeError: If the input_ is not a list[int], bytes, or ScaleBytes. """ if isinstance(input_, ScaleBytes): as_scale_bytes = input_ else: if isinstance(input_, list) and all([isinstance(i, int) for i in input_]): vec_u8 = input_ as_bytes = bytes(vec_u8) elif isinstance(input_, bytes): as_bytes = input_ else: raise TypeError("input_ must be a list[int], bytes, or ScaleBytes") as_scale_bytes = ScaleBytes(as_bytes) rpc_runtime_config = RuntimeConfiguration() rpc_runtime_config.update_type_registry(load_type_registry_preset("legacy")) rpc_runtime_config.update_type_registry(custom_rpc_type_registry) obj = rpc_runtime_config.create_scale_object(type_string, data=as_scale_bytes) return obj.decode()
custom_rpc_type_registry = { "types": { "SubnetInfo": { "type": "struct", "type_mapping": [ ["netuid", "Compact<u16>"], ["rho", "Compact<u16>"], ["kappa", "Compact<u16>"], ["difficulty", "Compact<u64>"], ["immunity_period", "Compact<u16>"], ["max_allowed_validators", "Compact<u16>"], ["min_allowed_weights", "Compact<u16>"], ["max_weights_limit", "Compact<u16>"], ["scaling_law_power", "Compact<u16>"], ["subnetwork_n", "Compact<u16>"], ["max_allowed_uids", "Compact<u16>"], ["blocks_since_last_step", "Compact<u64>"], ["tempo", "Compact<u16>"], ["network_modality", "Compact<u16>"], ["network_connect", "Vec<[u16; 2]>"], ["emission_values", "Compact<u64>"], ["burn", "Compact<u64>"], ["owner", "AccountId"], ], }, "DelegateInfo": { "type": "struct", "type_mapping": [ ["delegate_ss58", "AccountId"], ["take", "Compact<u16>"], ["nominators", "Vec<(AccountId, Compact<u64>)>"], ["owner_ss58", "AccountId"], ["registrations", "Vec<Compact<u16>>"], ["validator_permits", "Vec<Compact<u16>>"], ["return_per_1000", "Compact<u64>"], ["total_daily_return", "Compact<u64>"], ], }, "NeuronInfo": { "type": "struct", "type_mapping": [ ["hotkey", "AccountId"], ["coldkey", "AccountId"], ["uid", "Compact<u16>"], ["netuid", "Compact<u16>"], ["active", "bool"], ["axon_info", "axon_info"], ["prometheus_info", "PrometheusInfo"], ["stake", "Vec<(AccountId, Compact<u64>)>"], ["rank", "Compact<u16>"], ["emission", "Compact<u64>"], ["incentive", "Compact<u16>"], ["consensus", "Compact<u16>"], ["trust", "Compact<u16>"], ["validator_trust", "Compact<u16>"], ["dividends", "Compact<u16>"], ["last_update", "Compact<u64>"], ["validator_permit", "bool"], ["weights", "Vec<(Compact<u16>, Compact<u16>)>"], ["bonds", "Vec<(Compact<u16>, Compact<u16>)>"], ["pruning_score", "Compact<u16>"], ], }, "NeuronInfoLite": { "type": "struct", "type_mapping": [ ["hotkey", "AccountId"], ["coldkey", "AccountId"], ["uid", "Compact<u16>"], ["netuid", "Compact<u16>"], ["active", "bool"], ["axon_info", "axon_info"], ["prometheus_info", "PrometheusInfo"], ["stake", "Vec<(AccountId, Compact<u64>)>"], ["rank", "Compact<u16>"], ["emission", "Compact<u64>"], ["incentive", "Compact<u16>"], ["consensus", "Compact<u16>"], ["trust", "Compact<u16>"], ["validator_trust", "Compact<u16>"], ["dividends", "Compact<u16>"], ["last_update", "Compact<u64>"], ["validator_permit", "bool"], ["pruning_score", "Compact<u16>"], ], }, "axon_info": { "type": "struct", "type_mapping": [ ["block", "u64"], ["version", "u32"], ["ip", "u128"], ["port", "u16"], ["ip_type", "u8"], ["protocol", "u8"], ["placeholder1", "u8"], ["placeholder2", "u8"], ], }, "PrometheusInfo": { "type": "struct", "type_mapping": [ ["block", "u64"], ["version", "u32"], ["ip", "u128"], ["port", "u16"], ["ip_type", "u8"], ], }, "IPInfo": { "type": "struct", "type_mapping": [ ["ip", "Compact<u128>"], ["ip_type_and_protocol", "Compact<u8>"], ], }, "StakeInfo": { "type": "struct", "type_mapping": [ ["hotkey", "AccountId"], ["coldkey", "AccountId"], ["stake", "Compact<u64>"], ], }, "SubnetHyperparameters": { "type": "struct", "type_mapping": [ ["rho", "Compact<u16>"], ["kappa", "Compact<u16>"], ["immunity_period", "Compact<u16>"], ["min_allowed_weights", "Compact<u16>"], ["max_weights_limit", "Compact<u16>"], ["tempo", "Compact<u16>"], ["min_difficulty", "Compact<u64>"], ["max_difficulty", "Compact<u64>"], ["weights_version", "Compact<u64>"], ["weights_rate_limit", "Compact<u64>"], ["adjustment_interval", "Compact<u16>"], ["activity_cutoff", "Compact<u16>"], ["registration_allowed", "bool"], ["target_regs_per_interval", "Compact<u16>"], ["min_burn", "Compact<u64>"], ["max_burn", "Compact<u64>"], ["bonds_moving_avg", "Compact<u64>"], ["max_regs_per_block", "Compact<u16>"], ["serving_rate_limit", "Compact<u64>"], ["max_validators", "Compact<u16>"], ["adjustment_alpha", "Compact<u64>"], ["difficulty", "Compact<u64>"], ["commit_reveal_weights_interval", "Compact<u64>"], ["commit_reveal_weights_enabled", "bool"], ["alpha_high", "Compact<u16>"], ["alpha_low", "Compact<u16>"], ["liquid_alpha_enabled", "bool"], ], }, "ScheduledColdkeySwapInfo": { "type": "struct", "type_mapping": [ ["old_coldkey", "AccountId"], ["new_coldkey", "AccountId"], ["arbitration_block", "Compact<u64>"], ], }, } }
[docs] def decode_account_id(account_id_bytes: list) -> str: """ Decodes an AccountId from bytes to a Base64 string using SS58 encoding. Args: account_id_bytes (bytes): The AccountId in bytes that needs to be decoded. Returns: str: The decoded AccountId as a Base64 string. """ # Convert the AccountId bytes to a Base64 string return ss58_encode(bytes(account_id_bytes).hex(), SS58_FORMAT)
[docs] def process_stake_data(stake_data: list) -> dict: """ Processes stake data to decode account IDs and convert stakes from rao to Balance objects. Args: stake_data (list): A list of tuples where each tuple contains an account ID in bytes and a stake in rao. Returns: dict: A dictionary with account IDs as keys and their corresponding Balance objects as values. """ decoded_stake_data = {} for account_id_bytes, stake_ in stake_data: account_id = decode_account_id(account_id_bytes) decoded_stake_data.update({account_id: Balance.from_rao(stake_)}) return decoded_stake_data