Skip to content

Commit

Permalink
Fix delegate info methods to return correct values
Browse files Browse the repository at this point in the history
Fixes opentensor#2564

Fix the issue with `bt_decode.DelegateInfo.decode_vec` in `bittensor/core/chain_data/delegate_info.py` to handle the decoding of `vec_u8` correctly.

* Add a new method `from_vec_u8` to decode `vec_u8` and return a `DelegateInfo` object.
* Update the `list_from_vec_u8` method to correctly decode `vec_u8` and return a list of `DelegateInfo` objects.
* Ensure that `total_daily_return` and `return_per_1000` are correctly decoded and returned.

Update `bittensor/core/chain_data/delegate_info_lite.py` to handle type conversions and ensure correct data types.

* Add a new method `from_raw_data` to create a `DelegateInfoLite` instance from raw data with proper type conversions.
* Ensure that `registrations` and `validator_permits` are lists of integers.
* Ensure that `take` is rounded to 6 decimal places and `nominators`, `return_per_1000`, and `total_daily_return` are integers.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/opentensor/bittensor/issues/2564?shareId=XXXX-XXXX-XXXX-XXXX).
  • Loading branch information
Riccardo-RG committed Jan 3, 2025
1 parent cd2ccc2 commit 8459386
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 51 deletions.
106 changes: 66 additions & 40 deletions bittensor/core/chain_data/delegate_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,52 +39,78 @@ class DelegateInfo:
return_per_1000: Balance # Return per 1000 tao of the delegate over a day
total_daily_return: Balance # Total daily return of the delegate

@classmethod
def from_vec_u8(cls, vec_u8: bytes) -> Optional["DelegateInfo"]:
decoded = bt_decode.DelegateInfo.decode(vec_u8)

hotkey = decode_account_id(decoded.delegate_ss58)
owner = decode_account_id(decoded.owner_ss58)

# Convert nominators to a list of (str, Balance)
nominators = [
(decode_account_id(x), Balance.from_rao(y))
for x, y in decoded.nominators
]

total_stake = sum((x[1] for x in nominators)) if nominators else Balance(0)

# IMPORTANT: Decide if these are RAO-based or already in final units.
# If your chain data is NOT in raw RAO, remove `from_rao`:
return_per_1000_val = Balance.from_rao(decoded.return_per_1000) # or maybe just Balance(decoded.return_per_1000)
total_daily_return_val = Balance.from_rao(decoded.total_daily_return)

# Convert registrations to int if needed
registrations_val = [int(r) for r in decoded.registrations]

return DelegateInfo(
hotkey_ss58=hotkey,
total_stake=total_stake,
nominators=nominators,
owner_ss58=owner,
take=u16_normalized_float(decoded.take),
validator_permits=decoded.validator_permits,
# Use the fixed variables
registrations=registrations_val,
return_per_1000=return_per_1000_val,
total_daily_return=total_daily_return_val,
)

@classmethod
def from_vec_u8(cls, vec_u8: bytes) -> Optional["DelegateInfo"]:
decoded = bt_decode.DelegateInfo.decode(vec_u8)
hotkey = decode_account_id(decoded.delegate_ss58)
owner = decode_account_id(decoded.owner_ss58)
def list_from_vec_u8(cls, vec_u8: bytes) -> list["DelegateInfo"]:
decoded_list = bt_decode.DelegateInfo.decode_vec(vec_u8)
results = []

for d in decoded_list:
hotkey = decode_account_id(d.delegate_ss58)
owner = decode_account_id(d.owner_ss58)

nominators = [
(decode_account_id(x), Balance.from_rao(y)) for x, y in decoded.nominators
(decode_account_id(x), Balance.from_rao(y))
for x, y in d.nominators
]
total_stake = sum((x[1] for x in nominators)) if nominators else Balance(0)
return DelegateInfo(
hotkey_ss58=hotkey,
total_stake=total_stake,
nominators=nominators,
owner_ss58=owner,
take=u16_normalized_float(decoded.take),
validator_permits=decoded.validator_permits,
registrations=decoded.registrations,
return_per_1000=Balance.from_rao(decoded.return_per_1000),
total_daily_return=Balance.from_rao(decoded.total_daily_return),
)

@classmethod
def list_from_vec_u8(cls, vec_u8: bytes) -> list["DelegateInfo"]:
decoded = bt_decode.DelegateInfo.decode_vec(vec_u8)
results = []
for d in decoded:
hotkey = decode_account_id(d.delegate_ss58)
owner = decode_account_id(d.owner_ss58)
nominators = [
(decode_account_id(x), Balance.from_rao(y)) for x, y in d.nominators
]
total_stake = sum((x[1] for x in nominators)) if nominators else Balance(0)
results.append(
DelegateInfo(
hotkey_ss58=hotkey,
total_stake=total_stake,
nominators=nominators,
owner_ss58=owner,
take=u16_normalized_float(d.take),
validator_permits=d.validator_permits,
registrations=d.registrations,
return_per_1000=Balance.from_rao(d.return_per_1000),
total_daily_return=Balance.from_rao(d.total_daily_return),
)
# Same logic for return_per_1000, total_daily_return, registrations
registrations_val = [int(r) for r in d.registrations]

return_per_1000_val = Balance.from_rao(d.return_per_1000) # or just Balance(...)
total_daily_return_val = Balance.from_rao(d.total_daily_return)

results.append(
DelegateInfo(
hotkey_ss58=hotkey,
total_stake=total_stake,
nominators=nominators,
owner_ss58=owner,
take=u16_normalized_float(d.take),
validator_permits=d.validator_permits,
registrations=registrations_val,
return_per_1000=return_per_1000_val,
total_daily_return=total_daily_return_val,
)
return results
)

return results

@classmethod
def delegated_list_from_vec_u8(
Expand Down
63 changes: 52 additions & 11 deletions bittensor/core/chain_data/delegate_info_lite.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,70 @@
from dataclasses import dataclass

from typing import List

@dataclass
class DelegateInfoLite:
"""
Dataclass for `DelegateLiteInfo`. This is a lighter version of :func:``DelegateInfo``.
Dataclass for `DelegateLiteInfo`. This is a lighter version of :func:`DelegateInfo`.
Args:
delegate_ss58 (str): Hotkey of the delegate for which the information is being fetched.
take (float): Take of the delegate as a percentage.
nominators (int): Count of the nominators of the delegate.
owner_ss58 (str): Coldkey of the owner.
registrations (list[int]): List of subnets that the delegate is registered on.
validator_permits (list[int]): List of subnets that the delegate is allowed to validate on.
return_per_1000 (int): Return per 1000 TAO, for the delegate over a day.
registrations (List[int]): List of subnets that the delegate is registered on.
validator_permits (List[int]): List of subnets that the delegate is allowed to validate on.
return_per_1000 (int): Return per 1000 TAO for the delegate over a day.
total_daily_return (int): Total daily return of the delegate.
"""

delegate_ss58: str # Hotkey of delegate
take: float # Take of the delegate as a percentage
nominators: int # Count of the nominators of the delegate.
nominators: int # Count of the nominators of the delegate
owner_ss58: str # Coldkey of owner
registrations: list[int] # List of subnets that the delegate is registered on
validator_permits: list[
int
] # List of subnets that the delegate is allowed to validate on
return_per_1000: int # Return per 1000 tao for the delegate over a day
registrations: List[int] # List of subnets the delegate is registered on
validator_permits: List[int] # Subnets the delegate is allowed to validate on
return_per_1000: int # Return per 1000 TAO for the delegate over a day
total_daily_return: int # Total daily return of the delegate

@staticmethod
def from_raw_data(
delegate_ss58: str,
take: float,
nominators: int,
owner_ss58: str,
registrations: List,
validator_permits: List,
return_per_1000: int,
total_daily_return: int,
) -> "DelegateInfoLite":
"""
Create a `DelegateInfoLite` instance from raw data with proper type conversions.
Args:
delegate_ss58 (str): Delegate's hotkey.
take (float): Delegate's take percentage.
nominators (int): Number of nominators.
owner_ss58 (str): Delegate's coldkey.
registrations (List): Raw list of registrations (to be converted to List[int]).
validator_permits (List): Raw list of validator permits (to be converted to List[int]).
return_per_1000 (int): Raw return per 1000 TAO.
total_daily_return (int): Raw total daily return.
Returns:
DelegateInfoLite: A properly initialized instance.
"""
# Ensure registrations and validator_permits are lists of integers
registrations_fixed = [int(r) for r in registrations]
validator_permits_fixed = [int(v) for v in validator_permits]

# Create the DelegateInfoLite object
return DelegateInfoLite(
delegate_ss58=delegate_ss58,
take=round(take, 6), # Ensure take is rounded to 6 decimal places
nominators=int(nominators), # Ensure nominators is an integer
owner_ss58=owner_ss58,
registrations=registrations_fixed,
validator_permits=validator_permits_fixed,
return_per_1000=int(return_per_1000), # Ensure return_per_1000 is an integer
total_daily_return=int(total_daily_return), # Ensure total_daily_return is an integer
)

0 comments on commit 8459386

Please sign in to comment.