Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Staging] add stake info runtime api #1505

Merged
merged 12 commits into from
Sep 27, 2023
22 changes: 22 additions & 0 deletions bittensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,28 @@ def turn_console_off():
},
}
},
"StakeInfoRuntimeApi": {
"methods": {
"get_stake_info_for_coldkey": {
"params": [
{
"name": "coldkey_account_vec",
"type": "Vec<u8>",
},
],
"type": "Vec<u8>",
},
"get_stake_info_for_coldkeys": {
"params": [
{
"name": "coldkey_account_vecs",
"type": "Vec<Vec<u8>>",
},
],
"type": "Vec<u8>",
},
},
},
},
}

Expand Down
103 changes: 94 additions & 9 deletions bittensor/_subtensor/chain_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@
["ip_type", "u8"],
],
},
"StakeInfo": {
"type": "struct",
"type_mapping": [
["hotkey", "AccountId"],
["coldkey", "AccountId"],
["stake", "Compact<u64>"],
],
},
}
}

Expand All @@ -149,6 +157,7 @@ class ChainDataType(Enum):
DelegateInfo = 3
NeuronInfoLite = 4
DelegatedInfo = 5
StakeInfo = 7


# Constants
Expand All @@ -162,6 +171,21 @@ def from_scale_encoding(
type_name: ChainDataType,
is_vec: bool = False,
is_option: bool = False,
) -> Optional[Dict]:
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)


def from_scale_encoding_using_type_string(
input: Union[List[int], bytes, ScaleBytes], type_string: str
) -> Optional[Dict]:
if isinstance(input, ScaleBytes):
as_scale_bytes = input
Expand All @@ -180,15 +204,6 @@ def from_scale_encoding(
rpc_runtime_config.update_type_registry(load_type_registry_preset("legacy"))
rpc_runtime_config.update_type_registry(custom_rpc_type_registry)

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}>"

obj = rpc_runtime_config.create_scale_object(type_string, data=as_scale_bytes)

return obj.decode()
Expand Down Expand Up @@ -646,6 +661,76 @@ def delegated_list_from_vec_u8(
return decoded


@dataclass
class StakeInfo:
r"""
Dataclass for stake info.
"""
hotkey_ss58: str # Hotkey address
coldkey_ss58: str # Coldkey address
stake: Balance # Stake for the hotkey-coldkey pair

@classmethod
def fix_decoded_values(cls, decoded: Any) -> "StakeInfo":
r"""Fixes the decoded values."""

return cls(
hotkey_ss58=ss58_encode(decoded["hotkey"], bittensor.__ss58_format__),
coldkey_ss58=ss58_encode(decoded["coldkey"], bittensor.__ss58_format__),
stake=Balance.from_rao(decoded["stake"]),
)

@classmethod
def from_vec_u8(cls, vec_u8: List[int]) -> Optional["StakeInfo"]:
r"""Returns a StakeInfo object from a vec_u8."""
if len(vec_u8) == 0:
return None

decoded = from_scale_encoding(vec_u8, ChainDataType.StakeInfo)

if decoded is None:
return None

decoded = StakeInfo.fix_decoded_values(decoded)

return decoded

@classmethod
def list_of_tuple_from_vec_u8(
cls, vec_u8: List[int]
) -> Dict[str, List["StakeInfo"]]:
r"""Returns a list of StakeInfo objects from a vec_u8."""
decoded: Optional[
List[Tuple(str, List[object])]
] = from_scale_encoding_using_type_string(
input=vec_u8, type_string="Vec<(AccountId, Vec<StakeInfo>)>"
)

if decoded is None:
return {}

stake_map = {
ss58_encode(address=account_id, ss58_format=bittensor.__ss58_format__): [
StakeInfo.fix_decoded_values(d) for d in stake_info
]
for account_id, stake_info in decoded
}

return stake_map

@classmethod
def list_from_vec_u8(cls, vec_u8: List[int]) -> List["StakeInfo"]:
r"""Returns a list of StakeInfo objects from a vec_u8."""
decoded = from_scale_encoding(vec_u8, ChainDataType.StakeInfo, is_vec=True)

if decoded is None:
return []

decoded = [StakeInfo.fix_decoded_values(d) for d in decoded]

return decoded


@dataclass
class SubnetInfo:
r"""
Expand Down
68 changes: 63 additions & 5 deletions bittensor/_subtensor/subtensor_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@

from bittensor._subtensor.chain_data import custom_rpc_type_registry
from bittensor.utils.balance import Balance
from bittensor.utils import U16_NORMALIZED_FLOAT, U64_MAX, RAOPERTAO, U16_MAX
from bittensor.utils import (
U16_NORMALIZED_FLOAT,
U64_MAX,
RAOPERTAO,
U16_MAX,
ss58_to_vec_u8,
)
from bittensor.utils.registration import POWSolution

# Local imports.
Expand All @@ -37,6 +43,7 @@
DelegateInfo,
PrometheusInfo,
SubnetInfo,
StakeInfo,
NeuronInfoLite,
axon_info,
ProposalVoteData,
Expand Down Expand Up @@ -1569,8 +1576,7 @@ def make_substrate_call_with_retry(encoded_hotkey: List[int]):
params=params,
)

hotkey_bytes: bytes = bittensor.utils.ss58_address_to_bytes(hotkey_ss58)
encoded_hotkey: List[int] = [int(byte) for byte in hotkey_bytes]
encoded_hotkey = ss58_to_vec_u8(hotkey_ss58)
json_body = make_substrate_call_with_retry(encoded_hotkey)
result = json_body["result"]

Expand Down Expand Up @@ -1617,8 +1623,7 @@ def make_substrate_call_with_retry(encoded_coldkey: List[int]):
params=params,
)

coldkey_bytes: bytes = bittensor.utils.ss58_address_to_bytes(coldkey_ss58)
encoded_coldkey: List[int] = [int(byte) for byte in coldkey_bytes]
encoded_coldkey = ss58_to_vec_u8(coldkey_ss58)
json_body = make_substrate_call_with_retry(encoded_coldkey)
result = json_body["result"]

Expand All @@ -1627,6 +1632,59 @@ def make_substrate_call_with_retry(encoded_coldkey: List[int]):

return DelegateInfo.delegated_list_from_vec_u8(result)

###########################
#### Stake Information ####
###########################

def get_stake_info_for_colkey(
self, coldkey_ss58: str, block: Optional[int] = None
) -> List[Tuple[DelegateInfo, Balance]]:
"""Returns the list of StakeInfo objects for this coldkey"""

encoded_coldkey = ss58_to_vec_u8(coldkey_ss58)

hex_bytes_result = self.query_runtime_api(
runtime_api="StakeInfoRuntimeApi",
method="get_stake_info_for_coldkey",
params=[encoded_coldkey],
block=block,
)

if hex_bytes_result == None:
return None

if hex_bytes_result.startswith("0x"):
bytes_result = bytes.fromhex(hex_bytes_result[2:])
else:
bytes_result = bytes.fromhex(hex_bytes_result)

return StakeInfo.list_from_vec_u8(bytes_result)

def get_stake_info_for_colkeys(
self, coldkey_ss58_list: List[str], block: Optional[int] = None
) -> List[Tuple[DelegateInfo, Balance]]:
"""Returns the list of StakeInfo objects for all coldkeys in the list."""
encoded_coldkeys = [
ss58_to_vec_u8(coldkey_ss58) for coldkey_ss58 in coldkey_ss58_list
]

hex_bytes_result = self.query_runtime_api(
runtime_api="StakeInfoRuntimeApi",
method="get_stake_info_for_coldkeys",
params=[encoded_coldkeys],
block=block,
)

if hex_bytes_result == None:
return None

if hex_bytes_result.startswith("0x"):
bytes_result = bytes.fromhex(hex_bytes_result[2:])
else:
bytes_result = bytes.fromhex(hex_bytes_result)

return StakeInfo.list_of_tuple_from_vec_u8(bytes_result)

########################################
#### Neuron information per subnet ####
########################################
Expand Down
6 changes: 6 additions & 0 deletions bittensor/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
U64_MAX = 18446744073709551615


def ss58_to_vec_u8(ss58_address: str) -> List[int]:
ss58_bytes: bytes = bittensor.utils.ss58_address_to_bytes(ss58_address)
encoded_address: List[int] = [int(byte) for byte in ss58_bytes]
return encoded_address


def indexed_values_to_dataframe(
prefix: Union[str, int],
index: Union[list, torch.LongTensor],
Expand Down