diff --git a/bittensor/core/chain_data/__init__.py b/bittensor/core/chain_data/__init__.py index 9ad1e38881..08f220861d 100644 --- a/bittensor/core/chain_data/__init__.py +++ b/bittensor/core/chain_data/__init__.py @@ -17,6 +17,7 @@ from .stake_info import StakeInfo from .subnet_hyperparameters import SubnetHyperparameters from .subnet_info import SubnetInfo +from .subnet_state import SubnetState from .utils import custom_rpc_type_registry ProposalCallData = GenericCall diff --git a/bittensor/core/chain_data/subnet_state.py b/bittensor/core/chain_data/subnet_state.py new file mode 100644 index 0000000000..ff1e3e6abf --- /dev/null +++ b/bittensor/core/chain_data/subnet_state.py @@ -0,0 +1,92 @@ +""" +This module defines the `SubnetState` data class and associated methods for handling and decoding +subnetwork states in the Bittensor network. +""" + +from dataclasses import dataclass +from typing import Optional + +from scalecodec.utils.ss58 import ss58_encode + +from bittensor.core.chain_data.utils import ( + ChainDataType, + from_scale_encoding, + SS58_FORMAT, +) +from bittensor.utils import u16_normalized_float +from bittensor.utils.balance import Balance + + +@dataclass +class SubnetState: + netuid: int + hotkeys: list[str] + coldkeys: list[str] + active: list[bool] + validator_permit: list[bool] + pruning_score: list[float] + last_update: list[int] + emission: list["Balance"] + dividends: list[float] + incentives: list[float] + consensus: list[float] + trust: list[float] + rank: list[float] + block_at_registration: list[int] + alpha_stake: list["Balance"] + tao_stake: list["Balance"] + total_stake: list["Balance"] + emission_history: list[list[int]] + + @classmethod + def from_vec_u8(cls, vec_u8: list[int]) -> Optional["SubnetState"]: + if len(vec_u8) == 0: + return None + decoded = from_scale_encoding(vec_u8, ChainDataType.SubnetState, is_option=True) + if decoded is None: + return None + return SubnetState.fix_decoded_values(decoded) + + @classmethod + def list_from_vec_u8(cls, vec_u8: list[int]) -> list["SubnetState"]: + decoded = from_scale_encoding( + vec_u8, ChainDataType.SubnetState, is_vec=True, is_option=True + ) + if decoded is None: + return [] + decoded = [SubnetState.fix_decoded_values(d) for d in decoded] + return decoded + + @classmethod + def fix_decoded_values(cls, decoded: dict) -> "SubnetState": + netuid = decoded["netuid"] + return SubnetState( + netuid=netuid, + hotkeys=[ss58_encode(val, SS58_FORMAT) for val in decoded["hotkeys"]], + coldkeys=[ss58_encode(val, SS58_FORMAT) for val in decoded["coldkeys"]], + active=decoded["active"], + validator_permit=decoded["validator_permit"], + pruning_score=[ + u16_normalized_float(val) for val in decoded["pruning_score"] + ], + last_update=decoded["last_update"], + emission=[ + Balance.from_rao(val).set_unit(netuid) for val in decoded["emission"] + ], + dividends=[u16_normalized_float(val) for val in decoded["dividends"]], + incentives=[u16_normalized_float(val) for val in decoded["incentives"]], + consensus=[u16_normalized_float(val) for val in decoded["consensus"]], + trust=[u16_normalized_float(val) for val in decoded["trust"]], + rank=[u16_normalized_float(val) for val in decoded["rank"]], + block_at_registration=decoded["block_at_registration"], + alpha_stake=[ + Balance.from_rao(val).set_unit(netuid) for val in decoded["alpha_stake"] + ], + tao_stake=[ + Balance.from_rao(val).set_unit(0) for val in decoded["tao_stake"] + ], + total_stake=[ + Balance.from_rao(val).set_unit(netuid) for val in decoded["total_stake"] + ], + emission_history=decoded["emission_history"], + ) diff --git a/bittensor/core/chain_data/utils.py b/bittensor/core/chain_data/utils.py index 9c21c9d22e..5b58d68ff4 100644 --- a/bittensor/core/chain_data/utils.py +++ b/bittensor/core/chain_data/utils.py @@ -22,6 +22,7 @@ class ChainDataType(Enum): SubnetHyperparameters = 8 ScheduledColdkeySwapInfo = 9 AccountId = 10 + SubnetState = 11 def from_scale_encoding( @@ -208,6 +209,29 @@ def from_scale_encoding_using_type_string( ["ip_type_and_protocol", "Compact"], ], }, + "SubnetState": { + "type": "struct", + "type_mapping": [ + ["netuid", "Compact"], + ["hotkeys", "Vec"], + ["coldkeys", "Vec"], + ["active", "Vec"], + ["validator_permit", "Vec"], + ["pruning_score", "Vec>"], + ["last_update", "Vec>"], + ["emission", "Vec>"], + ["dividends", "Vec>"], + ["incentives", "Vec>"], + ["consensus", "Vec>"], + ["trust", "Vec>"], + ["rank", "Vec>"], + ["block_at_registration", "Vec>"], + ["alpha_stake", "Vec>"], + ["tao_stake", "Vec>"], + ["total_stake", "Vec>"], + ["emission_history", "Vec>>"], + ], + }, "StakeInfo": { "type": "struct", "type_mapping": [ diff --git a/bittensor/core/metagraph.py b/bittensor/core/metagraph.py index 208eaa6b9f..0ff4ecf1bd 100644 --- a/bittensor/core/metagraph.py +++ b/bittensor/core/metagraph.py @@ -25,7 +25,11 @@ import numpy as np from numpy.typing import NDArray +from substrateinterface.exceptions import SubstrateRequestException +from bittensor.core import settings +from bittensor.core.chain_data import AxonInfo, SubnetState +from bittensor.utils.balance import Balance from bittensor.utils.btlogging import logging from bittensor.utils.registration import torch, use_torch from bittensor.utils.weight_utils import ( @@ -33,20 +37,15 @@ convert_bond_uids_and_vals_to_tensor, convert_root_weight_uids_and_vals_to_tensor, ) -from . import settings -from .chain_data import AxonInfo # For annotation purposes if typing.TYPE_CHECKING: from bittensor.core.subtensor import Subtensor - METAGRAPH_STATE_DICT_NDARRAY_KEYS = [ "version", "n", "block", - "stake", - "total_stake", "ranks", "trust", "consensus", @@ -66,8 +65,6 @@ - **version** (`str`): The version identifier of the metagraph state. - **n** (`int`): The total number of nodes in the metagraph. - **block** (`int`): The current block number in the blockchain or ledger. -- **stake** (`ndarray`): An array representing the stake of each node. -- **total_stake** (`float`): The sum of all individual stakes in the metagraph. - **ranks** (`ndarray`): An array of rank scores assigned to each node. - **trust** (`ndarray`): An array of trust scores for the nodes. - **consensus** (`ndarray`): An array indicating consensus levels among nodes. @@ -147,8 +144,6 @@ class MetagraphMixin(ABC): version (NDArray): The version number of the network, integral for tracking network updates. n (NDArray): The total number of neurons in the network, reflecting its size and complexity. block (NDArray): The current block number in the blockchain, crucial for synchronizing with the network's latest state. - stake: Represents the cryptocurrency staked by neurons, impacting their influence and earnings within the network. - total_stake: The cumulative stake across all neurons. ranks: Neuron rankings as per the Yuma Consensus algorithm, influencing their incentive distribution and network authority. trust: Scores indicating the reliability of neurons, mainly miners, within the network's operational context. consensus: Scores reflecting each neuron's alignment with the network's collective decisions. @@ -192,36 +187,54 @@ class MetagraphMixin(ABC): netuid: int network: str - version: Union["torch.nn.Parameter", tuple[NDArray]] - n: Union["torch.nn.Parameter", NDArray] - block: Union["torch.nn.Parameter", NDArray] - stake: Union["torch.nn.Parameter", NDArray] - total_stake: Union["torch.nn.Parameter", NDArray] - ranks: Union["torch.nn.Parameter", NDArray] - trust: Union["torch.nn.Parameter", NDArray] - consensus: Union["torch.nn.Parameter", NDArray] - validator_trust: Union["torch.nn.Parameter", NDArray] - incentive: Union["torch.nn.Parameter", NDArray] - emission: Union["torch.nn.Parameter", NDArray] - dividends: Union["torch.nn.Parameter", NDArray] - active: Union["torch.nn.Parameter", NDArray] - last_update: Union["torch.nn.Parameter", NDArray] - validator_permit: Union["torch.nn.Parameter", NDArray] - weights: Union["torch.nn.Parameter", NDArray] - bonds: Union["torch.nn.Parameter", NDArray] - uids: Union["torch.nn.Parameter", NDArray] - axons: list[AxonInfo] + version: Union["torch.nn.Parameter", tuple["NDArray"]] + n: Union["torch.nn.Parameter", "NDArray"] + block: Union["torch.nn.Parameter", "NDArray"] + ranks: Union["torch.nn.Parameter", "NDArray"] + trust: Union["torch.nn.Parameter", "NDArray"] + consensus: Union["torch.nn.Parameter", "NDArray"] + validator_trust: Union["torch.nn.Parameter", "NDArray"] + incentive: Union["torch.nn.Parameter", "NDArray"] + emission: Union["torch.nn.Parameter", "NDArray"] + dividends: Union["torch.nn.Parameter", "NDArray"] + active: Union["torch.nn.Parameter", "NDArray"] + last_update: Union["torch.nn.Parameter", "NDArray"] + validator_permit: Union["torch.nn.Parameter", "NDArray"] + weights: Union["torch.nn.Parameter", "NDArray"] + bonds: Union["torch.nn.Parameter", "NDArray"] + uids: Union["torch.nn.Parameter", "NDArray"] + alpha_stake: Union["torch.nn.Parameter", "NDArray"] + tao_stake: Union["torch.nn.Parameter", "NDArray"] + total_stake: Union["torch.nn.Parameter", "NDArray"] + axons: list["AxonInfo"] + + @property + def Ts(self) -> list["Balance"]: + """ + Represents the tao stake of each neuron in the Bittensor network. + + Returns: + list["Balance"]: The list of tao stake of each neuron in the network. + """ + return self.tao_stake @property - def S(self) -> Union[NDArray, "torch.nn.Parameter"]: + def AS(self) -> list["Balance"]: """ - Represents the stake of each neuron in the Bittensor network. Stake is an important concept in the - Bittensor ecosystem, signifying the amount of network weight (or “stake”) each neuron holds, - represented on a digital ledger. The stake influences a neuron's ability to contribute to and benefit - from the network, playing a crucial role in the distribution of incentives and decision-making processes. + Represents the alpha stake of each neuron in the Bittensor network. Returns: - NDArray: A tensor representing the stake of each neuron in the network. Higher values signify a greater stake held by the respective neuron. + list["Balance"]: The list of alpha stake of each neuron in the network. + """ + return self.alpha_stake + + @property + def S(self) -> list["Balance"]: + """ + Represents the total stake of each neuron in the Bittensor network. + + Returns: + list["Balance"]: The list of total stake of each neuron in the network. """ return self.total_stake @@ -492,8 +505,6 @@ def state_dict(self): "version": self.version, "n": self.n, "block": self.block, - "stake": self.stake, - "total_stake": self.total_stake, "ranks": self.ranks, "trust": self.trust, "consensus": self.consensus, @@ -509,6 +520,9 @@ def state_dict(self): "uids": self.uids, "axons": self.axons, "neurons": self.neurons, + "alpha_stake": self.alpha_stake, + "tao_stake": self.tao_stake, + "total_stake": self.total_stake, } def sync( @@ -578,6 +592,9 @@ def sync( if not lite: self._set_weights_and_bonds(subtensor=subtensor) + # Fills in the stake associated attributes of a class instance from a chain response. + self._get_all_stakes_from_chain(subtensor=subtensor) + def _initialize_subtensor(self, subtensor: "Subtensor"): """ Initializes the subtensor to be used for syncing the metagraph. @@ -725,7 +742,7 @@ def _process_weights_or_bonds( len(self.neurons), list(uids), list(values) ).astype(np.float32) ) - tensor_param: Union["torch.nn.Parameter", NDArray] = ( + tensor_param: Union["torch.nn.Parameter", "NDArray"] = ( ( torch.nn.Parameter(torch.stack(data_array), requires_grad=False) if len(data_array) @@ -748,6 +765,36 @@ def _process_weights_or_bonds( def _set_metagraph_attributes(self, block, subtensor): pass + def _get_all_stakes_from_chain(self, subtensor: "Subtensor"): + """Fills in the stake associated attributes of a class instance from a chain response.""" + try: + hex_bytes_result = subtensor.query_runtime_api( + runtime_api="SubnetInfoRuntimeApi", + method="get_subnet_state", + params=[self.netuid], + ) + + if hex_bytes_result is None: + logging.debug( + f"Unable to retrieve subnet state for netuid `{self.netuid}`." + ) + return [] + + if hex_bytes_result.startswith("0x"): + bytes_result = bytes.fromhex(hex_bytes_result[2:]) + else: + bytes_result = bytes.fromhex(hex_bytes_result) + + subnet_state: "SubnetState" = SubnetState.from_vec_u8(bytes_result) + self.alpha_stake = subnet_state.alpha_stake + self.tao_stake = subnet_state.tao_stake + self.total_stake = subnet_state.total_stake + + except (SubstrateRequestException, AttributeError): + logging.debug( + "Fields `alpha_stake`, `tao_stake`, `total_stake` can be obtained only from the RAO network." + ) + def _process_root_weights( self, data: list, attribute: str, subtensor: "Subtensor" ) -> Union[NDArray, "torch.nn.Parameter"]: @@ -939,12 +986,6 @@ def __init__( self.block: torch.nn.Parameter = torch.nn.Parameter( torch.tensor([0], dtype=torch.int64), requires_grad=False ) - self.stake = torch.nn.Parameter( - torch.tensor([], dtype=torch.float32), requires_grad=False - ) - self.total_stake: torch.nn.Parameter = torch.nn.Parameter( - torch.tensor([], dtype=torch.float32), requires_grad=False - ) self.ranks: torch.nn.Parameter = torch.nn.Parameter( torch.tensor([], dtype=torch.float32), requires_grad=False ) @@ -984,7 +1025,10 @@ def __init__( self.uids = torch.nn.Parameter( torch.tensor([], dtype=torch.int64), requires_grad=False ) - self.axons: list[AxonInfo] = [] + self.alpha_stake: list["Balance"] = [] + self.tao_stake: list["Balance"] = [] + self.total_stake: list["Balance"] = [] + self.axons: list["AxonInfo"] = [] if sync: self.sync(block=None, lite=lite) @@ -1046,12 +1090,6 @@ def _set_metagraph_attributes(self, block: int, subtensor: "Subtensor"): self.validator_trust = self._create_tensor( [neuron.validator_trust for neuron in self.neurons], dtype=torch.float32 ) - self.total_stake = self._create_tensor( - [neuron.total_stake.tao for neuron in self.neurons], dtype=torch.float32 - ) - self.stake = self._create_tensor( - [neuron.stake for neuron in self.neurons], dtype=torch.float32 - ) self.axons = [n.axon_info for n in self.neurons] def load_from_path(self, dir_path: str) -> "Metagraph": @@ -1080,10 +1118,6 @@ def load_from_path(self, dir_path: str) -> "Metagraph": self.n = torch.nn.Parameter(state_dict["n"], requires_grad=False) self.block = torch.nn.Parameter(state_dict["block"], requires_grad=False) self.uids = torch.nn.Parameter(state_dict["uids"], requires_grad=False) - self.stake = torch.nn.Parameter(state_dict["stake"], requires_grad=False) - self.total_stake = torch.nn.Parameter( - state_dict["total_stake"], requires_grad=False - ) self.ranks = torch.nn.Parameter(state_dict["ranks"], requires_grad=False) self.trust = torch.nn.Parameter(state_dict["trust"], requires_grad=False) self.consensus = torch.nn.Parameter( @@ -1115,6 +1149,18 @@ def load_from_path(self, dir_path: str) -> "Metagraph": ) if "bonds" in state_dict: self.bonds = torch.nn.Parameter(state_dict["bonds"], requires_grad=False) + if "alpha_stake" in state_dict: + self.alpha_stake = torch.nn.Parameter( + state_dict["alpha_stake"], requires_grad=False + ) + if "tao_stake" in state_dict: + self.tao_stake = torch.nn.Parameter( + state_dict["tao_stake"], requires_grad=False + ) + if "total_stake" in state_dict: + self.total_stake = torch.nn.Parameter( + state_dict["total_stake"], requires_grad=False + ) return self @@ -1148,8 +1194,6 @@ def __init__( self.version = (np.array([settings.version_as_int], dtype=np.int64),) self.n = np.array([0], dtype=np.int64) self.block = np.array([0], dtype=np.int64) - self.stake = np.array([], dtype=np.float32) - self.total_stake = np.array([], dtype=np.float32) self.ranks = np.array([], dtype=np.float32) self.trust = np.array([], dtype=np.float32) self.consensus = np.array([], dtype=np.float32) @@ -1163,7 +1207,10 @@ def __init__( self.weights = np.array([], dtype=np.float32) self.bonds = np.array([], dtype=np.int64) self.uids = np.array([], dtype=np.int64) - self.axons: list[AxonInfo] = [] + self.alpha_stake: list["Balance"] = [] + self.tao_stake: list["Balance"] = [] + self.total_stake: list["Balance"] = [] + self.axons: list["AxonInfo"] = [] if sync: self.sync(block=None, lite=lite) @@ -1221,12 +1268,6 @@ def _set_metagraph_attributes(self, block: int, subtensor: "Subtensor"): self.validator_trust = self._create_tensor( [neuron.validator_trust for neuron in self.neurons], dtype=np.float32 ) - self.total_stake = self._create_tensor( - [neuron.total_stake.tao for neuron in self.neurons], dtype=np.float32 - ) - self.stake = self._create_tensor( - [neuron.stake for neuron in self.neurons], dtype=np.float32 - ) self.axons = [n.axon_info for n in self.neurons] def load_from_path(self, dir_path: str) -> "Metagraph": @@ -1270,8 +1311,6 @@ def load_from_path(self, dir_path: str) -> "Metagraph": self.n = state_dict["n"] self.block = state_dict["block"] self.uids = state_dict["uids"] - self.stake = state_dict["stake"] - self.total_stake = state_dict["total_stake"] self.ranks = state_dict["ranks"] self.trust = state_dict["trust"] self.consensus = state_dict["consensus"] @@ -1288,6 +1327,12 @@ def load_from_path(self, dir_path: str) -> "Metagraph": self.weights = state_dict["weights"] if "bonds" in state_dict: self.bonds = state_dict["bonds"] + if "alpha_stake" in state_dict: + self.alpha_stake = state_dict["alpha_stake"] + if "tao_stake" in state_dict: + self.tao_stake = state_dict["tao_stake"] + if "total_stake" in state_dict: + self.total_stake = state_dict["total_stake"] return self diff --git a/bittensor/core/settings.py b/bittensor/core/settings.py index 29948b612e..147799ba15 100644 --- a/bittensor/core/settings.py +++ b/bittensor/core/settings.py @@ -61,22 +61,22 @@ def turn_console_on(): MINERS_DIR = USER_BITTENSOR_DIR / "miners" # Bittensor networks name -NETWORKS = ["local", "finney", "test", "archive"] - -DEFAULT_ENDPOINT = "wss://entrypoint-finney.opentensor.ai:443" -DEFAULT_NETWORK = NETWORKS[1] - -# Create dirs if they don't exist -WALLETS_DIR.mkdir(parents=True, exist_ok=True) -MINERS_DIR.mkdir(parents=True, exist_ok=True) - +NETWORKS = ["local", "finney", "test", "archive", "rao"] # Bittensor endpoints (Needs to use wss://) FINNEY_ENTRYPOINT = "wss://entrypoint-finney.opentensor.ai:443" FINNEY_TEST_ENTRYPOINT = "wss://test.finney.opentensor.ai:443/" ARCHIVE_ENTRYPOINT = "wss://archive.chain.opentensor.ai:443/" +RAO_ENDPOINT = "wss://rao.chain.opentensor.ai:443/" LOCAL_ENTRYPOINT = os.getenv("BT_SUBTENSOR_CHAIN_ENDPOINT") or "ws://127.0.0.1:9946" +DEFAULT_ENDPOINT = RAO_ENDPOINT +DEFAULT_NETWORK = NETWORKS[4] + +# Create dirs if they don't exist +WALLETS_DIR.mkdir(parents=True, exist_ok=True) +MINERS_DIR.mkdir(parents=True, exist_ok=True) + # Currency Symbols Bittensor TAO_SYMBOL: str = chr(0x03C4) RAO_SYMBOL: str = chr(0x03C1) @@ -228,17 +228,26 @@ def turn_console_on(): ], "type": "Vec", }, - "get_subnet_info": { + "get_all_dynamic_info": { + "params": [], + "type": "Vec", + }, + "get_subnet_info_v2": { + "params": [ + {"name": "netuid", "type": "u16"}, + ], + "type": "Vec", + }, + "get_dynamic_info": { "params": [ - { - "name": "netuid", - "type": "u16", - }, + {"name": "netuid", "type": "u16"}, ], "type": "Vec", }, - "get_subnets_info": { - "params": [], + "get_subnet_state": { + "params": [ + {"name": "netuid", "type": "u16"}, + ], "type": "Vec", }, } @@ -357,3 +366,139 @@ def __apply_nest_asyncio(): __apply_nest_asyncio() + +units = [ + "\u03c4", # τ (tau, 0) + "\u03b1", # α (alpha, 1) + "\u03b2", # β (beta, 2) + "\u03b3", # γ (gamma, 3) + "\u03b4", # δ (delta, 4) + "\u03b5", # ε (epsilon, 5) + "\u03b6", # ζ (zeta, 6) + "\u03b7", # η (eta, 7) + "\u03b8", # θ (theta, 8) + "\u03b9", # ι (iota, 9) + "\u03ba", # κ (kappa, 10) + "\u03bb", # λ (lambda, 11) + "\u03bc", # μ (mu, 12) + "\u03bd", # ν (nu, 13) + "\u03be", # ξ (xi, 14) + "\u03bf", # ο (omicron, 15) + "\u03c0", # π (pi, 16) + "\u03c1", # ρ (rho, 17) + "\u03c3", # σ (sigma, 18) + "t", # t (tau, 19) + "\u03c5", # υ (upsilon, 20) + "\u03c6", # φ (phi, 21) + "\u03c7", # χ (chi, 22) + "\u03c8", # ψ (psi, 23) + "\u03c9", # ω (omega, 24) + # Hebrew letters + "\u05d0", # א (aleph, 25) + "\u05d1", # ב (bet, 26) + "\u05d2", # ג (gimel, 27) + "\u05d3", # ד (dalet, 28) + "\u05d4", # ה (he, 29) + "\u05d5", # ו (vav, 30) + "\u05d6", # ז (zayin, 31) + "\u05d7", # ח (het, 32) + "\u05d8", # ט (tet, 33) + "\u05d9", # י (yod, 34) + "\u05da", # ך (final kaf, 35) + "\u05db", # כ (kaf, 36) + "\u05dc", # ל (lamed, 37) + "\u05dd", # ם (final mem, 38) + "\u05de", # מ (mem, 39) + "\u05df", # ן (final nun, 40) + "\u05e0", # נ (nun, 41) + "\u05e1", # ס (samekh, 42) + "\u05e2", # ע (ayin, 43) + "\u05e3", # ף (final pe, 44) + "\u05e4", # פ (pe, 45) + "\u05e5", # ץ (final tsadi, 46) + "\u05e6", # צ (tsadi, 47) + "\u05e7", # ק (qof, 48) + "\u05e8", # ר (resh, 49) + "\u05e9", # ש (shin, 50) + "\u05ea", # ת (tav, 51) + # Georgian Alphabet (Mkhedruli) + "\u10d0", # ა (Ani, 97) + "\u10d1", # ბ (Bani, 98) + "\u10d2", # გ (Gani, 99) + "\u10d3", # დ (Doni, 100) + "\u10d4", # ე (Eni, 101) + "\u10d5", # ვ (Vini, 102) + # Armenian Alphabet + "\u0531", # Ա (Ayp, 103) + "\u0532", # Բ (Ben, 104) + "\u0533", # Գ (Gim, 105) + "\u0534", # Դ (Da, 106) + "\u0535", # Ե (Ech, 107) + "\u0536", # Զ (Za, 108) + # "\u055e", # ՞ (Question mark, 109) + # Runic Alphabet + "\u16a0", # ᚠ (Fehu, wealth, 81) + "\u16a2", # ᚢ (Uruz, strength, 82) + "\u16a6", # ᚦ (Thurisaz, giant, 83) + "\u16a8", # ᚨ (Ansuz, god, 84) + "\u16b1", # ᚱ (Raidho, ride, 85) + "\u16b3", # ᚲ (Kaunan, ulcer, 86) + "\u16c7", # ᛇ (Eihwaz, yew, 87) + "\u16c9", # ᛉ (Algiz, protection, 88) + "\u16d2", # ᛒ (Berkanan, birch, 89) + # Cyrillic Alphabet + "\u0400", # Ѐ (Ie with grave, 110) + "\u0401", # Ё (Io, 111) + "\u0402", # Ђ (Dje, 112) + "\u0403", # Ѓ (Gje, 113) + "\u0404", # Є (Ukrainian Ie, 114) + "\u0405", # Ѕ (Dze, 115) + # Coptic Alphabet + "\u2c80", # Ⲁ (Alfa, 116) + "\u2c81", # ⲁ (Small Alfa, 117) + "\u2c82", # Ⲃ (Vida, 118) + "\u2c83", # ⲃ (Small Vida, 119) + "\u2c84", # Ⲅ (Gamma, 120) + "\u2c85", # ⲅ (Small Gamma, 121) + # Arabic letters + "\u0627", # ا (alef, 52) + "\u0628", # ب (ba, 53) + "\u062a", # ت (ta, 54) + "\u062b", # ث (tha, 55) + "\u062c", # ج (jeem, 56) + "\u062d", # ح (ha, 57) + "\u062e", # خ (kha, 58) + "\u062f", # د (dal, 59) + "\u0630", # ذ (dhal, 60) + "\u0631", # ر (ra, 61) + "\u0632", # ز (zay, 62) + "\u0633", # س (seen, 63) + "\u0634", # ش (sheen, 64) + "\u0635", # ص (sad, 65) + "\u0636", # ض (dad, 66) + "\u0637", # ط (ta, 67) + "\u0638", # ظ (dha, 68) + "\u0639", # ع (ain, 69) + "\u063a", # غ (ghain, 70) + "\u0641", # ف (fa, 71) + "\u0642", # ق (qaf, 72) + "\u0643", # ك (kaf, 73) + "\u0644", # ل (lam, 74) + "\u0645", # م (meem, 75) + "\u0646", # ن (noon, 76) + "\u0647", # ه (ha, 77) + "\u0648", # و (waw, 78) + "\u0649", # ى (alef maksura, 79) + "\u064a", # ي (ya, 80) + # Ogham Alphabet + "\u1680", #   (Space, 90) + "\u1681", # ᚁ (Beith, birch, 91) + "\u1682", # ᚂ (Luis, rowan, 92) + "\u1683", # ᚃ (Fearn, alder, 93) + "\u1684", # ᚄ (Sail, willow, 94) + "\u1685", # ᚅ (Nion, ash, 95) + "\u169b", # ᚛ (Forfeda, 96) + # Tifinagh Alphabet + "\u2d30", # ⴰ (Ya, 127) + "\u2d31", # ⴱ (Yab, 128) +] diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index ac6c46bc46..9613668edb 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -75,7 +75,12 @@ transfer_extrinsic, ) from bittensor.core.metagraph import Metagraph -from bittensor.utils import networking, torch, ss58_to_vec_u8, u16_normalized_float +from bittensor.utils import ( + networking, + torch, + ss58_to_vec_u8, + u16_normalized_float, +) from bittensor.utils.balance import Balance from bittensor.utils.btlogging import logging from bittensor.utils.registration import legacy_torch_api_compat @@ -357,7 +362,7 @@ def add_args(cls, parser: "argparse.ArgumentParser", prefix: Optional[str] = Non prefix_str = "" if prefix is None else f"{prefix}." try: default_network = settings.DEFAULT_NETWORK - default_chain_endpoint = settings.FINNEY_ENTRYPOINT + default_chain_endpoint = settings.DEFAULT_ENDPOINT parser.add_argument( f"--{prefix_str}subtensor.network", @@ -718,7 +723,7 @@ def determine_chain_endpoint_and_network( if network is None: return None, None - if network in ["finney", "local", "test", "archive"]: + if network in ["finney", "local", "test", "archive", "rao"]: if network == "finney": # Kiru Finney staging network. return network, settings.FINNEY_ENTRYPOINT @@ -728,6 +733,8 @@ def determine_chain_endpoint_and_network( return network, settings.FINNEY_TEST_ENTRYPOINT elif network == "archive": return network, settings.ARCHIVE_ENTRYPOINT + elif network == "rao": + return network, settings.RAO_ENDPOINT else: if ( network == settings.FINNEY_ENTRYPOINT @@ -744,6 +751,10 @@ def determine_chain_endpoint_and_network( or "archive.chain.opentensor.ai" in network ): return "archive", settings.ARCHIVE_ENTRYPOINT + elif ( + network == settings.RAO_ENDPOINT or "rao.chain.opentensor.ai" in network + ): + return "rao", settings.RAO_ENDPOINT elif "127.0.0.1" in network or "localhost" in network: return "local", network else: diff --git a/bittensor/utils/balance.py b/bittensor/utils/balance.py index 016db373a4..cecff54f6c 100644 --- a/bittensor/utils/balance.py +++ b/bittensor/utils/balance.py @@ -68,17 +68,26 @@ def __float__(self): def __str__(self): """Returns the Balance object as a string in the format "symbolvalue", where the value is in tao.""" - return f"{self.unit}{float(self.tao):,.9f}" + if self.unit == settings.units[0]: + return f"{self.unit} {float(self.tao):,.4f}" + else: + return f"{float(self.tao):,.4f} {self.unit}\u200e" def __rich__(self): - int_tao, fract_tao = format(float(self.tao), "f").split(".") - return f"[green]{self.unit}[/green][green]{int_tao}[/green][green].[/green][dim green]{fract_tao}[/dim green]" + return "[green]{}[/green][green]{}[/green][green].[/green][dim green]{}[/dim green]".format( + self.unit, + format(float(self.tao), "f").split(".")[0], + format(float(self.tao), "f").split(".")[1], + ) def __str_rao__(self): return f"{self.rao_unit}{int(self.rao)}" def __rich_rao__(self): - return f"[green]{self.rao_unit}{int(self.rao)}[/green]" + if settings.units.index(self.unit) != 0: + return f"[green]{int(self.rao)}{self.unit}[/green]" + else: + return f"[green]{self.unit}\u200e{int(self.rao)}[/green]" def __repr__(self): return self.__str__() @@ -265,4 +274,22 @@ def from_rao(amount: int): Returns: A Balance object representing the given amount. """ - return Balance(amount) + return Balance(int(amount)) + + @staticmethod + def get_unit(netuid: int): + units = settings.units + base = len(units) + if netuid < base: + return units[netuid] + else: + result = "" + while netuid > 0: + result = units[netuid % base] + result + netuid //= base + return result + + def set_unit(self, netuid: int): + self.unit = Balance.get_unit(netuid) + self.rao_unit = Balance.get_unit(netuid) + return self diff --git a/bittensor/utils/mock/subtensor_mock.py b/bittensor/utils/mock/subtensor_mock.py index 817be08434..9cc5cb6167 100644 --- a/bittensor/utils/mock/subtensor_mock.py +++ b/bittensor/utils/mock/subtensor_mock.py @@ -544,6 +544,15 @@ def query_map_subtensor( else: return MockMapResult([]) + def query_runtime_api( + self, + runtime_api: str, + method: str, + params: Optional[Union[list[int], dict[str, int]]], + block: Optional[int] = None, + ) -> Optional[str]: + return None + def query_constant( self, module_name: str, constant_name: str, block: Optional[int] = None ) -> Optional[object]: diff --git a/requirements/prod.txt b/requirements/prod.txt index bed65e9d2e..3668e90775 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -2,7 +2,8 @@ wheel setuptools~=70.0.0 aiohttp~=3.9 backoff -bittensor-cli +# bittensor-cli +git+https://github.com/opentensor/btcli.git@rao#egg=bittensor-cli bt-decode colorama~=0.4.6 fastapi~=0.110.1 diff --git a/tests/integration_tests/test_metagraph_integration.py b/tests/integration_tests/test_metagraph_integration.py index 34bf4f590e..0f2eac0d30 100644 --- a/tests/integration_tests/test_metagraph_integration.py +++ b/tests/integration_tests/test_metagraph_integration.py @@ -15,11 +15,13 @@ # 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 bittensor -import torch import os -from bittensor.utils.mock import MockSubtensor + +import torch + from bittensor.core.metagraph import METAGRAPH_STATE_DICT_NDARRAY_KEYS, get_save_dir +from bittensor.core.metagraph import Metagraph +from bittensor.utils.mock import MockSubtensor _subtensor_mock: MockSubtensor = MockSubtensor() @@ -33,7 +35,7 @@ def setUpModule(): class TestMetagraph: def setup_method(self): self.sub = MockSubtensor() - self.metagraph = bittensor.Metagraph(netuid=3, network="mock", sync=False) + self.metagraph = Metagraph(netuid=3, network="mock", sync=False) def test_print_empty(self): print(self.metagraph) @@ -76,8 +78,9 @@ def test_state_dict(self): assert "version" in state assert "n" in state assert "block" in state - assert "stake" in state assert "total_stake" in state + assert "alpha_stake" in state + assert "tao_stake" in state assert "ranks" in state assert "trust" in state assert "consensus" in state @@ -98,7 +101,6 @@ def test_properties(self): metagraph.coldkeys metagraph.addresses metagraph.validator_trust - metagraph.S metagraph.R metagraph.I metagraph.E @@ -108,3 +110,6 @@ def test_properties(self): metagraph.D metagraph.B metagraph.W + metagraph.Ts + metagraph.AS + metagraph.S diff --git a/tests/integration_tests/test_subtensor_integration.py b/tests/integration_tests/test_subtensor_integration.py index 552e5ab993..1a81d18319 100644 --- a/tests/integration_tests/test_subtensor_integration.py +++ b/tests/integration_tests/test_subtensor_integration.py @@ -77,8 +77,10 @@ def test_network_overrides(self): """Tests that the network overrides the chain_endpoint.""" # Argument importance: chain_endpoint (arg) > network (arg) > config.subtensor.chain_endpoint > config.subtensor.network config0 = bittensor.Subtensor.config() - config0.subtensor.network = "finney" - config0.subtensor.chain_endpoint = "wss://finney.subtensor.io" # Should not match bittensor.core.settings.FINNEY_ENTRYPOINT + config0.subtensor.network = settings.DEFAULT_NETWORK + config0.subtensor.chain_endpoint = ( + settings.RAO_ENDPOINT + ) # Should not match bittensor.core.settings.FINNEY_ENTRYPOINT assert config0.subtensor.chain_endpoint != settings.FINNEY_ENTRYPOINT config1 = bittensor.Subtensor.config() @@ -246,8 +248,8 @@ def test_get_balance(self): def test_defaults_to_finney(self): sub = bittensor.Subtensor() - assert sub.network == "finney" - assert sub.chain_endpoint == settings.FINNEY_ENTRYPOINT + assert sub.network == settings.DEFAULT_NETWORK + assert sub.chain_endpoint == settings.DEFAULT_ENDPOINT def test_registration_multiprocessed_already_registered(self): work_blocks_before_is_registered = random.randint(5, 10) diff --git a/tests/unit_tests/test_metagraph.py b/tests/unit_tests/test_metagraph.py index e4dca70a1d..b3cf293ddf 100644 --- a/tests/unit_tests/test_metagraph.py +++ b/tests/unit_tests/test_metagraph.py @@ -142,6 +142,7 @@ def metagraph_instance(): metagraph._assign_neurons = MagicMock() metagraph._set_metagraph_attributes = MagicMock() metagraph._set_weights_and_bonds = MagicMock() + metagraph._get_all_stakes_from_chain = MagicMock() return metagraph