Skip to content

Commit a918df1

Browse files
authored
Merge pull request #2605 from opentensor/feat/roman/brigh-chain-metagraph
[RAO] Add methods to fetch metagraph data from the chain
2 parents 02dcbc0 + 0837148 commit a918df1

File tree

10 files changed

+955
-32
lines changed

10 files changed

+955
-32
lines changed

bittensor/core/async_subtensor.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
from scalecodec.base import RuntimeConfiguration
1515
from scalecodec.type_registry import load_type_registry_preset
1616

17-
from bittensor.core.types import SubtensorMixin
1817
from bittensor.core.chain_data import (
1918
DelegateInfo,
2019
StakeInfo,
20+
MetagraphInfo,
2121
NeuronInfoLite,
2222
NeuronInfo,
2323
ProposalVoteData,
@@ -60,6 +60,7 @@
6060
from bittensor.core.metagraph import AsyncMetagraph
6161
from bittensor.core.settings import version_as_int, TYPE_REGISTRY, DELEGATES_DETAILS_URL
6262
from bittensor.core.types import ParamWithTypes
63+
from bittensor.core.types import SubtensorMixin
6364
from bittensor.utils import (
6465
decode_hex_identity_dict,
6566
format_error_message,
@@ -1282,6 +1283,33 @@ async def get_minimum_required_stake(self):
12821283

12831284
return Balance.from_rao(getattr(result, "value", 0))
12841285

1286+
async def get_metagraph_info(
1287+
self, netuid: int, block: Optional[int] = None
1288+
) -> Optional[MetagraphInfo]:
1289+
block_hash = await self.get_block_hash(block)
1290+
1291+
query = await self.substrate.runtime_call(
1292+
"SubnetInfoRuntimeApi",
1293+
"get_metagraph",
1294+
params=[netuid],
1295+
block_hash=block_hash,
1296+
)
1297+
metagraph_bytes = bytes.fromhex(query.decode()[2:])
1298+
return MetagraphInfo.from_vec_u8(metagraph_bytes)
1299+
1300+
async def get_all_metagraphs_info(
1301+
self, block: Optional[int] = None
1302+
) -> list[MetagraphInfo]:
1303+
block_hash = await self.get_block_hash(block)
1304+
1305+
query = await self.substrate.runtime_call(
1306+
"SubnetInfoRuntimeApi",
1307+
"get_all_metagraphs",
1308+
block_hash=block_hash,
1309+
)
1310+
metagraphs_bytes = bytes.fromhex(query.decode()[2:])
1311+
return MetagraphInfo.list_from_vec_u8(metagraphs_bytes)
1312+
12851313
async def get_netuids_for_hotkey(
12861314
self,
12871315
hotkey_ss58: str,

bittensor/core/chain_data/__init__.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,50 @@
66
from scalecodec.types import GenericCall
77

88
from .axon_info import AxonInfo
9+
from .chain_identity import ChainIdentity
910
from .delegate_info import DelegateInfo
1011
from .delegate_info_lite import DelegateInfoLite
12+
from .dynamic_info import DynamicInfo
1113
from .ip_info import IPInfo
14+
from .metagraph_info import MetagraphInfo
1215
from .neuron_info import NeuronInfo
1316
from .neuron_info_lite import NeuronInfoLite
1417
from .neuron_certificate import NeuronCertificate
1518
from .prometheus_info import PrometheusInfo
1619
from .proposal_vote_data import ProposalVoteData
1720
from .scheduled_coldkey_swap_info import ScheduledColdkeySwapInfo
18-
from .subnet_state import SubnetState
1921
from .stake_info import StakeInfo
2022
from .subnet_hyperparameters import SubnetHyperparameters
21-
from .subnet_info import SubnetInfo
22-
from .dynamic_info import DynamicInfo
2323
from .subnet_identity import SubnetIdentity
24+
from .subnet_info import SubnetInfo
25+
from .subnet_state import SubnetState
2426
from .weight_commit_info import WeightCommitInfo
2527
from .utils import custom_rpc_type_registry, decode_account_id, process_stake_data
2628

2729
ProposalCallData = GenericCall
30+
31+
__all__ = [
32+
AxonInfo,
33+
ChainIdentity,
34+
DelegateInfo,
35+
DelegateInfoLite,
36+
DynamicInfo,
37+
IPInfo,
38+
MetagraphInfo,
39+
NeuronInfo,
40+
NeuronInfoLite,
41+
NeuronCertificate,
42+
PrometheusInfo,
43+
ProposalCallData,
44+
ProposalVoteData,
45+
ScheduledColdkeySwapInfo,
46+
StakeInfo,
47+
SubnetHyperparameters,
48+
SubnetIdentity,
49+
SubnetInfo,
50+
SubnetState,
51+
WeightCommitInfo,
52+
custom_rpc_type_registry,
53+
decode_account_id,
54+
process_stake_data,
55+
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass
5+
class ChainIdentity:
6+
"""Dataclass for chain identity information."""
7+
8+
# In `bittensor.core.chain_data.utils.custom_rpc_type_registry` represents as `ChainIdentityOf` structure.
9+
10+
name: str
11+
url: str
12+
image: str
13+
discord: str
14+
description: str
15+
additional: str
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
from dataclasses import dataclass
2+
from typing import Optional
3+
4+
from bittensor.core.chain_data.axon_info import AxonInfo
5+
from bittensor.core.chain_data.chain_identity import ChainIdentity
6+
from bittensor.core.chain_data.subnet_identity import SubnetIdentity
7+
from bittensor.core.chain_data.utils import (
8+
ChainDataType,
9+
from_scale_encoding,
10+
)
11+
from bittensor.utils import u64_normalized_float as u64tf, u16_normalized_float as u16tf
12+
from bittensor.utils.balance import Balance
13+
from scalecodec.utils.ss58 import ss58_encode
14+
15+
16+
# to balance with unit (just shortcut)
17+
def _tbwu(val: int, netuid: Optional[int] = 0) -> Balance:
18+
"""Returns a Balance object from a value and unit."""
19+
return Balance.from_tao(val, netuid)
20+
21+
22+
@dataclass
23+
class MetagraphInfo:
24+
# Subnet index
25+
netuid: int
26+
27+
# Name and symbol
28+
name: str
29+
symbol: str
30+
identity: Optional[SubnetIdentity]
31+
network_registered_at: int
32+
33+
# Keys for owner.
34+
owner_hotkey: str # hotkey
35+
owner_coldkey: str # coldkey
36+
37+
# Tempo terms.
38+
block: int # block at call.
39+
tempo: int # epoch tempo
40+
last_step: int
41+
blocks_since_last_step: int
42+
43+
# Subnet emission terms
44+
subnet_emission: Balance # subnet emission via tao
45+
alpha_in: Balance # amount of alpha in reserve
46+
alpha_out: Balance # amount of alpha outstanding
47+
tao_in: Balance # amount of tao injected per block
48+
alpha_out_emission: Balance # amount injected in alpha reserves per block
49+
alpha_in_emission: Balance # amount injected outstanding per block
50+
tao_in_emission: Balance # amount of tao injected per block
51+
pending_alpha_emission: Balance # pending alpha to be distributed
52+
pending_root_emission: Balance # pending tao for root divs to be distributed
53+
54+
# Hparams for epoch
55+
rho: int # subnet rho param
56+
kappa: float # subnet kappa param
57+
58+
# Validator params
59+
min_allowed_weights: float # min allowed weights per val
60+
max_weights_limit: float # max allowed weights per val
61+
weights_version: int # allowed weights version
62+
weights_rate_limit: int # rate limit on weights.
63+
activity_cutoff: int # validator weights cut off period in blocks
64+
max_validators: int # max allowed validators.
65+
66+
# Registration
67+
num_uids: int
68+
max_uids: int
69+
burn: Balance # current burn cost.
70+
difficulty: float # current difficulty.
71+
registration_allowed: bool # allows registrations.
72+
pow_registration_allowed: bool # pow registration enabled.
73+
immunity_period: int # subnet miner immunity period
74+
min_difficulty: float # min pow difficulty
75+
max_difficulty: float # max pow difficulty
76+
min_burn: Balance # min tao burn
77+
max_burn: Balance # max tao burn
78+
adjustment_alpha: float # adjustment speed for registration params.
79+
adjustment_interval: int # pow and burn adjustment interval
80+
target_regs_per_interval: int # target registrations per interval
81+
max_regs_per_block: int # max registrations per block.
82+
serving_rate_limit: int # axon serving rate limit
83+
84+
# CR
85+
commit_reveal_weights_enabled: bool # Is CR enabled.
86+
commit_reveal_period: int # Commit reveal interval
87+
88+
# Bonds
89+
liquid_alpha_enabled: bool # Bonds liquid enabled.
90+
alpha_high: float # Alpha param high
91+
alpha_low: float # Alpha param low
92+
bonds_moving_avg: float # Bonds moving avg
93+
94+
# Metagraph info.
95+
hotkeys: list[str] # hotkey per UID
96+
coldkeys: list[str] # coldkey per UID
97+
identities: list[Optional[ChainIdentity]] # coldkeys identities
98+
axons: list[AxonInfo] # UID axons.
99+
active: list[bool] # Active per UID
100+
validator_permit: list[bool] # Val permit per UID
101+
pruning_score: list[float] # Pruning per UID
102+
last_update: list[int] # Last update per UID
103+
emission: list[Balance] # Emission per UID
104+
dividends: list[float] # Dividends per UID
105+
incentives: list[float] # Mining incentives per UID
106+
consensus: list[float] # Consensus per UID
107+
trust: list[float] # Trust per UID
108+
rank: list[float] # Rank per UID
109+
block_at_registration: list[int] # Reg block per UID
110+
alpha_stake: list[Balance] # Alpha staked per UID
111+
tao_stake: list[Balance] # TAO staked per UID
112+
total_stake: list[Balance] # Total stake per UID
113+
114+
# Dividend break down.
115+
tao_dividends_per_hotkey: list[
116+
tuple[str, Balance]
117+
] # List of dividend payouts in tao via root.
118+
alpha_dividends_per_hotkey: list[
119+
tuple[str, Balance]
120+
] # List of dividend payout in alpha via subnet.
121+
122+
@classmethod
123+
def from_vec_u8(cls, vec_u8: bytes) -> Optional["MetagraphInfo"]:
124+
"""Returns a Metagraph object from encoded MetagraphInfo vector."""
125+
if len(vec_u8) == 0:
126+
return None
127+
decoded = from_scale_encoding(vec_u8, ChainDataType.MetagraphInfo)
128+
if decoded is None:
129+
return None
130+
131+
return MetagraphInfo.fix_decoded_values(decoded)
132+
133+
@classmethod
134+
def list_from_vec_u8(cls, vec_u8: bytes) -> list["MetagraphInfo"]:
135+
"""Returns a list of Metagraph objects from a list of encoded MetagraphInfo vectors."""
136+
decoded = from_scale_encoding(
137+
vec_u8, ChainDataType.MetagraphInfo, is_vec=True, is_option=True
138+
)
139+
if decoded is None:
140+
return []
141+
142+
decoded = [
143+
MetagraphInfo.fix_decoded_values(meta)
144+
for meta in decoded
145+
if meta is not None
146+
]
147+
return decoded
148+
149+
@classmethod
150+
def fix_decoded_values(cls, decoded: dict) -> "MetagraphInfo":
151+
"""Returns a Metagraph object from a decoded MetagraphInfo dictionary."""
152+
# Subnet index
153+
_netuid = decoded["netuid"]
154+
155+
# Name and symbol
156+
decoded.update({"name": bytes(decoded.get("name")).decode()})
157+
decoded.update({"symbol": bytes(decoded.get("symbol")).decode()})
158+
decoded.update({"identity": decoded.get("identity", {})})
159+
160+
# Keys for owner.
161+
decoded["owner_hotkey"] = ss58_encode(decoded["owner_hotkey"])
162+
decoded["owner_coldkey"] = ss58_encode(decoded["owner_coldkey"])
163+
164+
# Subnet emission terms
165+
decoded["subnet_emission"] = _tbwu(decoded["subnet_emission"])
166+
decoded["alpha_in"] = _tbwu(decoded["alpha_in"], _netuid)
167+
decoded["alpha_out"] = _tbwu(decoded["alpha_out"], _netuid)
168+
decoded["tao_in"] = _tbwu(decoded["tao_in"])
169+
decoded["alpha_out_emission"] = _tbwu(decoded["alpha_out_emission"], _netuid)
170+
decoded["alpha_in_emission"] = _tbwu(decoded["alpha_in_emission"], _netuid)
171+
decoded["tao_in_emission"] = _tbwu(decoded["tao_in_emission"])
172+
decoded["pending_alpha_emission"] = _tbwu(
173+
decoded["pending_alpha_emission"], _netuid
174+
)
175+
decoded["pending_root_emission"] = _tbwu(decoded["pending_root_emission"])
176+
177+
# Hparams for epoch
178+
decoded["kappa"] = u16tf(decoded["kappa"])
179+
180+
# Validator params
181+
decoded["min_allowed_weights"] = u16tf(decoded["min_allowed_weights"])
182+
decoded["max_weights_limit"] = u16tf(decoded["max_weights_limit"])
183+
184+
# Registration
185+
decoded["burn"] = _tbwu(decoded["burn"])
186+
decoded["difficulty"] = u64tf(decoded["difficulty"])
187+
decoded["min_difficulty"] = u64tf(decoded["min_difficulty"])
188+
decoded["max_difficulty"] = u64tf(decoded["max_difficulty"])
189+
decoded["min_burn"] = _tbwu(decoded["min_burn"])
190+
decoded["max_burn"] = _tbwu(decoded["max_burn"])
191+
decoded["adjustment_alpha"] = u64tf(decoded["adjustment_alpha"])
192+
193+
# Bonds
194+
decoded["alpha_high"] = u16tf(decoded["alpha_high"])
195+
decoded["alpha_low"] = u16tf(decoded["alpha_low"])
196+
decoded["bonds_moving_avg"] = u64tf(decoded["bonds_moving_avg"])
197+
198+
# Metagraph info.
199+
decoded["hotkeys"] = [ss58_encode(ck) for ck in decoded.get("hotkeys", [])]
200+
decoded["coldkeys"] = [ss58_encode(hk) for hk in decoded.get("coldkeys", [])]
201+
decoded["axons"] = decoded.get("axons", [])
202+
decoded["pruning_score"] = [
203+
u16tf(ps) for ps in decoded.get("pruning_score", [])
204+
]
205+
decoded["emission"] = [_tbwu(em, _netuid) for em in decoded.get("emission", [])]
206+
decoded["dividends"] = [u16tf(dv) for dv in decoded.get("dividends", [])]
207+
decoded["incentives"] = [u16tf(ic) for ic in decoded.get("incentives", [])]
208+
decoded["consensus"] = [u16tf(cs) for cs in decoded.get("consensus", [])]
209+
decoded["trust"] = [u16tf(tr) for tr in decoded.get("trust", [])]
210+
decoded["rank"] = [u16tf(rk) for rk in decoded.get("trust", [])]
211+
decoded["alpha_stake"] = [_tbwu(ast, _netuid) for ast in decoded["alpha_stake"]]
212+
decoded["tao_stake"] = [_tbwu(ts) for ts in decoded["tao_stake"]]
213+
decoded["total_stake"] = [_tbwu(ts, _netuid) for ts in decoded["total_stake"]]
214+
215+
# Dividend break down
216+
decoded["tao_dividends_per_hotkey"] = [
217+
(ss58_encode(alpha[0]), _tbwu(alpha[1]))
218+
for alpha in decoded["tao_dividends_per_hotkey"]
219+
]
220+
decoded["alpha_dividends_per_hotkey"] = [
221+
(ss58_encode(adphk[0]), _tbwu(adphk[1], _netuid))
222+
for adphk in decoded["alpha_dividends_per_hotkey"]
223+
]
224+
225+
return MetagraphInfo(**decoded)

0 commit comments

Comments
 (0)