Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 26 additions & 66 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from functools import partial
from typing import Optional, Any, Union, Iterable, TYPE_CHECKING

import aiohttp
import asyncstdlib as a
import numpy as np
import scalecodec
Expand All @@ -28,6 +27,7 @@
decode_account_id,
DynamicInfo,
)
from bittensor.core.chain_data.chain_identity import ChainIdentity
from bittensor.core.chain_data.delegate_info import DelegatedInfo
from bittensor.core.chain_data.utils import decode_metadata
from bittensor.core.config import Config
Expand Down Expand Up @@ -68,15 +68,14 @@
reveal_weights_extrinsic,
)
from bittensor.core.metagraph import AsyncMetagraph
from bittensor.core.settings import version_as_int, TYPE_REGISTRY, DELEGATES_DETAILS_URL
from bittensor.core.settings import version_as_int, TYPE_REGISTRY
from bittensor.core.types import ParamWithTypes, SubtensorMixin
from bittensor.utils import (
Certificate,
decode_hex_identity_dict,
format_error_message,
torch,
u16_normalized_float,
_decode_hex_identity_dict,
Certificate,
u64_normalized_float,
)
from bittensor.utils.balance import (
Expand All @@ -85,7 +84,6 @@
check_and_convert_to_balance,
)
from bittensor.utils.btlogging import logging
from bittensor.utils.delegates_details import DelegatesDetails
from bittensor.utils.weight_utils import generate_weight_hash

if TYPE_CHECKING:
Expand Down Expand Up @@ -1079,75 +1077,33 @@ async def get_delegate_identities(
block: Optional[int] = None,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> dict[str, "DelegatesDetails"]:
) -> dict[str, ChainIdentity]:
"""
Fetches delegates identities from the chain and GitHub. Preference is given to chain data, and missing info is
filled-in by the info from GitHub. At some point, we want to totally move away from fetching this info from
GitHub, but chain data is still limited in that regard.
Fetches delegates identities from the chain.

Arguments:
block (Optional[int]): The blockchain block number for the query.
block_hash (str): the hash of the blockchain block for the query
reuse_block (bool): Whether to reuse the last-used blockchain block hash.

Returns:
Dict {ss58: DelegatesDetails, ...}
Dict {ss58: ChainIdentity, ...}

"""
block_hash = await self.determine_block_hash(block, block_hash, reuse_block)
timeout = aiohttp.ClientTimeout(10.0)
async with aiohttp.ClientSession(timeout=timeout) as session:
identities_info, response = await asyncio.gather(
self.substrate.query_map(
module="Registry",
storage_function="IdentityOf",
block_hash=block_hash,
reuse_block_hash=reuse_block,
),
session.get(DELEGATES_DETAILS_URL),
)

all_delegates_details = {}
async for ss58_address, identity in identities_info:
all_delegates_details.update(
{
decode_account_id(
ss58_address[0]
): DelegatesDetails.from_chain_data(
decode_hex_identity_dict(identity.value["info"])
)
}
)

if response.ok:
all_delegates: dict[str, Any] = await response.json(content_type=None)

for delegate_hotkey, delegate_details in all_delegates.items():
delegate_info = all_delegates_details.setdefault(
delegate_hotkey,
DelegatesDetails(
display=delegate_details.get("name", ""),
web=delegate_details.get("url", ""),
additional=delegate_details.get("description", ""),
pgp_fingerprint=delegate_details.get("fingerprint", ""),
),
)
delegate_info.display = (
delegate_info.display or delegate_details.get("name", "")
)
delegate_info.web = delegate_info.web or delegate_details.get(
"url", ""
)
delegate_info.additional = (
delegate_info.additional
or delegate_details.get("description", "")
)
delegate_info.pgp_fingerprint = (
delegate_info.pgp_fingerprint
or delegate_details.get("fingerprint", "")
)
identities = await self.substrate.query_map(
module="SubtensorModule",
storage_function="IdentitiesV2",
block_hash=block_hash,
reuse_block_hash=reuse_block,
)

return all_delegates_details
return {
decode_account_id(ss58_address[0]): ChainIdentity.from_dict(
decode_hex_identity_dict(identity.value),
)
async for ss58_address, identity in identities
}

async def get_delegate_take(
self,
Expand Down Expand Up @@ -2424,7 +2380,7 @@ async def query_identity(
block: Optional[int] = None,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> dict:
) -> Optional[ChainIdentity]:
"""
Queries the identity of a neuron on the Bittensor blockchain using the given key. This function retrieves
detailed identity information about a specific neuron, which is a crucial aspect of the network's
Expand Down Expand Up @@ -2455,12 +2411,16 @@ async def query_identity(
block_hash=block_hash,
reuse_block_hash=reuse_block,
)

if not identity_info:
return {}
return None

try:
return _decode_hex_identity_dict(identity_info)
return ChainIdentity.from_dict(
decode_hex_identity_dict(identity_info),
)
except TypeError:
return {}
return None

async def recycle(
self,
Expand Down
3 changes: 0 additions & 3 deletions bittensor/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@
# Wallet ss58 address length
SS58_ADDRESS_LENGTH = 48

# Raw GitHub url for delegates registry file
DELEGATES_DETAILS_URL = "https://raw.githubusercontent.com/opentensor/bittensor-delegates/main/public/delegates.json"

# Block Explorers map network to explorer url
# Must all be polkadotjs explorer urls
NETWORK_EXPLORER_MAP = {
Expand Down
87 changes: 28 additions & 59 deletions bittensor/core/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
from typing import TYPE_CHECKING, Any, Iterable, Optional, Union, cast

import numpy as np
import requests
import scalecodec
from async_substrate_interface.errors import SubstrateRequestException
from async_substrate_interface.types import ScaleObj
from async_substrate_interface.sync_substrate import SubstrateInterface
from async_substrate_interface.utils import json
from numpy.typing import NDArray

from bittensor.core.async_subtensor import ProposalVoteData
Expand All @@ -29,6 +27,7 @@
DelegatedInfo,
decode_account_id,
)
from bittensor.core.chain_data.chain_identity import ChainIdentity
from bittensor.core.chain_data.utils import decode_metadata
from bittensor.core.config import Config
from bittensor.core.extrinsics.commit_reveal import commit_reveal_v3_extrinsic
Expand Down Expand Up @@ -71,16 +70,14 @@
version_as_int,
SS58_FORMAT,
TYPE_REGISTRY,
DELEGATES_DETAILS_URL,
)
from bittensor.core.types import ParamWithTypes, SubtensorMixin
from bittensor.utils import (
torch,
format_error_message,
Certificate,
decode_hex_identity_dict,
format_error_message,
torch,
u16_normalized_float,
_decode_hex_identity_dict,
Certificate,
u64_normalized_float,
)
from bittensor.utils.balance import (
Expand All @@ -90,7 +87,6 @@
check_and_convert_to_balance,
)
from bittensor.utils.btlogging import logging
from bittensor.utils.delegates_details import DelegatesDetails
from bittensor.utils.weight_utils import generate_weight_hash

if TYPE_CHECKING:
Expand Down Expand Up @@ -815,62 +811,29 @@ def get_delegate_by_hotkey(

def get_delegate_identities(
self, block: Optional[int] = None
) -> dict[str, "DelegatesDetails"]:
) -> dict[str, ChainIdentity]:
"""
Fetches delegates identities from the chain and GitHub. Preference is given to chain data, and missing info is
filled-in by the info from GitHub. At some point, we want to totally move away from fetching this info from
GitHub, but chain data is still limited in that regard.
Fetches delegates identities from the chain.

Arguments:
block (Optional[int]): The blockchain block number for the query.

Returns:
Dict {ss58: DelegatesDetails, ...}
Dict {ss58: ChainIdentity, ...}

"""
block_hash = self.determine_block_hash(block)
response = requests.get(DELEGATES_DETAILS_URL)
identities_info = self.substrate.query_map(
module="Registry", storage_function="IdentityOf", block_hash=block_hash
)

all_delegates_details = {}
for ss58_address, identity in identities_info:
all_delegates_details.update(
{
decode_account_id(
ss58_address[0]
): DelegatesDetails.from_chain_data(
decode_hex_identity_dict(identity.value["info"])
)
}
)
if response.ok:
all_delegates: dict[str, Any] = json.loads(response.content)

for delegate_hotkey, delegate_details in all_delegates.items():
delegate_info = all_delegates_details.setdefault(
delegate_hotkey,
DelegatesDetails(
display=delegate_details.get("name", ""),
web=delegate_details.get("url", ""),
additional=delegate_details.get("description", ""),
pgp_fingerprint=delegate_details.get("fingerprint", ""),
),
)
delegate_info.display = delegate_info.display or delegate_details.get(
"name", ""
)
delegate_info.web = delegate_info.web or delegate_details.get("url", "")
delegate_info.additional = (
delegate_info.additional or delegate_details.get("description", "")
)
delegate_info.pgp_fingerprint = (
delegate_info.pgp_fingerprint
or delegate_details.get("fingerprint", "")
)
identities = self.substrate.query_map(
module="SubtensorModule",
storage_function="IdentitiesV2",
block_hash=self.determine_block_hash(block),
)

return all_delegates_details
return {
decode_account_id(ss58_address[0]): ChainIdentity.from_dict(
decode_hex_identity_dict(identity.value),
)
for ss58_address, identity in identities
}

def get_delegate_take(
self, hotkey_ss58: str, block: Optional[int] = None
Expand Down Expand Up @@ -1843,7 +1806,9 @@ def neurons_lite(

return NeuronInfoLite.list_from_dicts(result)

def query_identity(self, coldkey_ss58: str, block: Optional[int] = None) -> dict:
def query_identity(
self, coldkey_ss58: str, block: Optional[int] = None
) -> Optional[ChainIdentity]:
"""
Queries the identity of a neuron on the Bittensor blockchain using the given key. This function retrieves
detailed identity information about a specific neuron, which is a crucial aspect of the network's
Expand All @@ -1870,12 +1835,16 @@ def query_identity(self, coldkey_ss58: str, block: Optional[int] = None) -> dict
params=[coldkey_ss58],
block_hash=self.determine_block_hash(block),
)

if not identity_info:
return {}
return None

try:
return _decode_hex_identity_dict(identity_info)
return ChainIdentity.from_dict(
decode_hex_identity_dict(identity_info),
)
except TypeError:
return {}
return None

def recycle(self, netuid: int, block: Optional[int] = None) -> Optional[Balance]:
"""
Expand Down
Loading
Loading