"""
This module defines the `AxonInfo` class, a data structure used to represent information about an axon endpoint
in the bittensor network.
"""
from dataclasses import asdict, dataclass
from typing import Any, Union
import netaddr
from async_substrate_interface.utils import json
from bittensor.core.chain_data.info_base import InfoBase
from bittensor.utils import networking
from bittensor.utils.btlogging import logging
from bittensor.utils.registration import torch, use_torch
[docs]
@dataclass
class AxonInfo(InfoBase):
"""
The `AxonInfo` class represents information about an axon endpoint in the bittensor network. This includes
properties such as IP address, ports, and relevant keys.
Attributes:
version (int): The version of the axon endpoint.
ip (str): The IP address of the axon endpoint.
port (int): The port number the axon endpoint uses.
ip_type (int): The type of IP protocol (e.g., IPv4 or IPv6).
hotkey (str): The hotkey associated with the axon endpoint.
coldkey (str): The coldkey associated with the axon endpoint.
protocol (int): The protocol version (default is 4).
placeholder1 (int): Reserved field (default is 0).
placeholder2 (int): Reserved field (default is 0).
"""
version: int
ip: str
port: int
ip_type: int
hotkey: str
coldkey: str
protocol: int = 4
placeholder1: int = 0
placeholder2: int = 0
@property
def is_serving(self) -> bool:
"""True if the endpoint is serving."""
return self.ip != "0.0.0.0"
[docs]
def ip_str(self) -> str:
"""Return the whole IP as string"""
return networking.ip__str__(self.ip_type, self.ip, self.port)
def __eq__(self, other: "AxonInfo"):
if other is None:
return False
if (
self.version == other.version
and self.ip == other.ip
and self.port == other.port
and self.ip_type == other.ip_type
and self.coldkey == other.coldkey
and self.hotkey == other.hotkey
):
return True
return False
def __str__(self):
return f"AxonInfo( {self.ip_str()}, {self.hotkey}, {self.coldkey}, {self.version} )"
def __repr__(self):
return self.__str__()
[docs]
def to_string(self) -> str:
"""Converts the `AxonInfo` object to a string representation using JSON."""
try:
return json.dumps(asdict(self))
except (TypeError, ValueError) as e:
logging.error(f"Error converting AxonInfo to string: {e}")
return AxonInfo(0, "", 0, 0, "", "").to_string()
@classmethod
def _from_dict(cls, data):
"""Returns a AxonInfo object from decoded chain data."""
return AxonInfo(
version=data["version"],
ip=str(netaddr.IPAddress(data["ip"])),
port=data["port"],
ip_type=data["ip_type"],
placeholder1=data["placeholder1"],
placeholder2=data["placeholder2"],
protocol=data["protocol"],
hotkey=data["hotkey"],
coldkey=data["coldkey"],
)
[docs]
@classmethod
def from_string(cls, json_string: str) -> "AxonInfo":
"""
Creates an `AxonInfo` object from its string representation using JSON.
Args:
json_string (str): The JSON string representation of the AxonInfo object.
Returns:
AxonInfo: An instance of AxonInfo created from the JSON string. If decoding fails, returns a default
`AxonInfo` object with default values.
Raises:
json.JSONDecodeError: If there is an error in decoding the JSON string.
TypeError: If there is a type error when creating the AxonInfo object.
ValueError: If there is a value error when creating the AxonInfo object.
"""
try:
data = json.loads(json_string)
return cls(**data)
except json.JSONDecodeError as e:
logging.error(f"Error decoding JSON: {e}")
except TypeError as e:
logging.error(f"Type error: {e}")
except ValueError as e:
logging.error(f"Value error: {e}")
return AxonInfo(0, "", 0, 0, "", "")
[docs]
@classmethod
def from_neuron_info(cls, neuron_info: dict) -> "AxonInfo":
"""
Converts a dictionary to an `AxonInfo` object.
Args:
neuron_info (dict): A dictionary containing the neuron information.
Returns:
instance (AxonInfo): An instance of AxonInfo created from the dictionary.
"""
return cls(
version=neuron_info["axon_info"]["version"],
ip=networking.int_to_ip(int(neuron_info["axon_info"]["ip"])),
port=neuron_info["axon_info"]["port"],
ip_type=neuron_info["axon_info"]["ip_type"],
hotkey=neuron_info["hotkey"],
coldkey=neuron_info["coldkey"],
)
[docs]
def to_parameter_dict(
self,
) -> Union[dict[str, Union[int, str]], "torch.nn.ParameterDict"]:
"""Returns a torch tensor or dict of the subnet info, depending on the USE_TORCH flag set."""
if use_torch():
return torch.nn.ParameterDict(self.__dict__)
else:
return self.__dict__
[docs]
@classmethod
def from_parameter_dict(
cls, parameter_dict: Union[dict[str, Any], "torch.nn.ParameterDict"]
) -> "AxonInfo":
"""Returns an axon_info object from a torch parameter_dict or a parameter dict."""
if use_torch():
return cls(**dict(parameter_dict))
else:
return cls(**parameter_dict)