From 44a64f7db2978394e70596a9fcdc18b224aa1429 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Mon, 13 Mar 2023 16:00:54 -0400 Subject: [PATCH 1/4] get custom rpc info from vec u8 --- bittensor/_subtensor/chain_data.py | 52 +++++++++++++++++++++++++- bittensor/_subtensor/subtensor_impl.py | 20 ++++++---- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/bittensor/_subtensor/chain_data.py b/bittensor/_subtensor/chain_data.py index 84a30649b6..d04a2e19eb 100644 --- a/bittensor/_subtensor/chain_data.py +++ b/bittensor/_subtensor/chain_data.py @@ -19,7 +19,7 @@ from typing import List, Tuple, Dict import bittensor from bittensor import Balance -import scalecodec +import json import torch @@ -28,6 +28,14 @@ U16_MAX = 65535 U64_MAX = 18446744073709551615 +def json_from_vec_u8( vec_u8: List[int] ) -> Dict: + r""" Returns a json dictionary from a bytes object. + """ + as_bytes = bytes(vec_u8) + as_json_str = as_bytes.decode('utf-8') + as_json = json.loads(as_json_str) + return as_json + # Dataclasses for chain data. @dataclass class NeuronInfo: @@ -57,6 +65,20 @@ class NeuronInfo: axon_info: 'AxonInfo' is_null: bool = False + @classmethod + def from_vec_u8(cls, vec_u8: List[int]) -> 'NeuronInfo': + r""" Returns a NeuronInfo object from a vec_u8. + """ + json = json_from_vec_u8(vec_u8) + return NeuronInfo.from_json(json) + + @classmethod + def list_from_vec_u8(cls, vec_u8: List[int]) -> List['NeuronInfo']: + r""" Returns a list of NeuronInfo objects from a vec_u8. + """ + json = json_from_vec_u8(vec_u8) + return [NeuronInfo.from_json(neuron) for neuron in json] + @classmethod def from_json(cls, json: Dict) -> 'NeuronInfo': r""" Returns a NeuronInfo object from a json dictionary. @@ -194,6 +216,20 @@ class DelegateInfo: owner_ss58: str # Coldkey of owner take: float # Take of the delegate as a percentage + @classmethod + def from_vec_u8(cls, vec_u8: List[int]) -> 'DelegateInfo': + r""" Returns a DelegateInfo object from a vec_u8. + """ + json = json_from_vec_u8(vec_u8) + return DelegateInfo.from_json(json) + + @classmethod + def list_from_vec_u8(cls, vec_u8: List[int]) -> List['DelegateInfo']: + r""" Returns a list of DelegateInfo objects from a vec_u8. + """ + json = json_from_vec_u8(vec_u8) + return [DelegateInfo.from_json(delegate) for delegate in json] + @classmethod def from_json(cls, json: Dict) -> 'DelegateInfo': r""" Returns a DelegateInfo object from a json dictionary. @@ -243,6 +279,20 @@ class SubnetInfo: connection_requirements: Dict[str, int] # netuid -> connection requirements emission_value: float + @classmethod + def from_vec_u8(cls, vec_u8: List[int]) -> 'SubnetInfo': + r""" Returns a SubnetInfo object from a vec_u8. + """ + json = json_from_vec_u8(vec_u8) + return SubnetInfo.from_json(json) + + @classmethod + def list_from_vec_u8(cls, vec_u8: List[int]) -> List['SubnetInfo']: + r""" Returns a list of SubnetInfo objects from a vec_u8. + """ + json = json_from_vec_u8(vec_u8) + return [SubnetInfo.from_json(subnet) for subnet in json] + @classmethod def from_json(cls, json: Dict) -> 'SubnetInfo': r""" Returns a SubnetInfo object from a json dictionary. diff --git a/bittensor/_subtensor/subtensor_impl.py b/bittensor/_subtensor/subtensor_impl.py index 646f64b7e6..82546e5a80 100644 --- a/bittensor/_subtensor/subtensor_impl.py +++ b/bittensor/_subtensor/subtensor_impl.py @@ -633,7 +633,7 @@ def make_substrate_call_with_retry(): if result == None: return [] - return [ SubnetInfo.from_json(subnet_info) for subnet_info in result ] + return SubnetInfo.list_from_vec_u8( result ) def get_subnet_info( self, netuid: int, block: Optional[int] = None ) -> Optional[SubnetInfo]: @retry(delay=2, tries=3, backoff=2, max_delay=4) @@ -654,7 +654,7 @@ def make_substrate_call_with_retry(): if result == None: return None - return SubnetInfo.from_json(result) + return SubnetInfo.from_vec_u8( result ) #################### #### Nomination #### @@ -688,10 +688,12 @@ def make_substrate_call_with_retry(encoded_hotkey: List[int]): hotkey_bytes: bytes = bittensor.utils.ss58_address_to_bytes( hotkey_ss58 ) encoded_hotkey: List[int] = [ int( byte ) for byte in hotkey_bytes ] json_body = make_substrate_call_with_retry(encoded_hotkey) - if json_body['result'] == None: + result = json_body['result'] + + if result == None: return None - return DelegateInfo.from_json( json_body['result'] ) + return DelegateInfo.from_vec_u8( result ) def get_delegates( self, block: Optional[int] = None ) -> List[DelegateInfo]: @retry(delay=2, tries=3, backoff=2, max_delay=4) @@ -706,10 +708,12 @@ def make_substrate_call_with_retry(): params=params ) json_body = make_substrate_call_with_retry() - if json_body['result'] == None: + result = json_body['result'] + + if result == None: return [] - return [DelegateInfo.from_json( delegate ) for delegate in json_body['result']] + return DelegateInfo.list_from_vec_u8( result ) ######################################## @@ -781,7 +785,7 @@ def make_substrate_call_with_retry(): json_body = make_substrate_call_with_retry() if json_body['result'] == None: return NeuronInfo._null_neuron() - return NeuronInfo.from_json( json_body['result'] ) + return NeuronInfo.from_vec_u8( json_body['result'] ) def neurons(self, netuid: int, block: Optional[int] = None ) -> List[NeuronInfo]: r""" Returns a list of neuron from the chain. @@ -809,7 +813,7 @@ def make_substrate_call_with_retry(): json_body = make_substrate_call_with_retry() result = json_body['result'] - return [ NeuronInfo.from_json( neuron ) for neuron in result ] + return NeuronInfo.list_from_vec_u8( result ) def metagraph( self, netuid: int, block: Optional[int] = None ) -> 'bittensor.Metagraph': r""" Returns the metagraph for the subnet. From aeedb0c0d220708ccba1d29e55a5cf461c55dfb2 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Mon, 13 Mar 2023 16:14:49 -0400 Subject: [PATCH 2/4] include check in parser --- bittensor/_subtensor/chain_data.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/bittensor/_subtensor/chain_data.py b/bittensor/_subtensor/chain_data.py index d04a2e19eb..e971791db7 100644 --- a/bittensor/_subtensor/chain_data.py +++ b/bittensor/_subtensor/chain_data.py @@ -16,7 +16,7 @@ # DEALINGS IN THE SOFTWARE. from dataclasses import dataclass -from typing import List, Tuple, Dict +from typing import List, Tuple, Dict, Optional import bittensor from bittensor import Balance import json @@ -28,9 +28,12 @@ U16_MAX = 65535 U64_MAX = 18446744073709551615 -def json_from_vec_u8( vec_u8: List[int] ) -> Dict: +def json_from_vec_u8( vec_u8: List[int] ) -> Optional[Dict]: r""" Returns a json dictionary from a bytes object. """ + if len(vec_u8) == 0: + return None + as_bytes = bytes(vec_u8) as_json_str = as_bytes.decode('utf-8') as_json = json.loads(as_json_str) @@ -70,6 +73,9 @@ def from_vec_u8(cls, vec_u8: List[int]) -> 'NeuronInfo': r""" Returns a NeuronInfo object from a vec_u8. """ json = json_from_vec_u8(vec_u8) + if json is None: + return NeuronInfo._null_neuron() # return null neuron instead of None + return NeuronInfo.from_json(json) @classmethod @@ -77,6 +83,9 @@ def list_from_vec_u8(cls, vec_u8: List[int]) -> List['NeuronInfo']: r""" Returns a list of NeuronInfo objects from a vec_u8. """ json = json_from_vec_u8(vec_u8) + if json is None: + return [] + return [NeuronInfo.from_json(neuron) for neuron in json] @classmethod @@ -217,10 +226,13 @@ class DelegateInfo: take: float # Take of the delegate as a percentage @classmethod - def from_vec_u8(cls, vec_u8: List[int]) -> 'DelegateInfo': + def from_vec_u8(cls, vec_u8: List[int]) -> Optional['DelegateInfo']: r""" Returns a DelegateInfo object from a vec_u8. """ json = json_from_vec_u8(vec_u8) + if json is None: + return None + return DelegateInfo.from_json(json) @classmethod @@ -228,6 +240,9 @@ def list_from_vec_u8(cls, vec_u8: List[int]) -> List['DelegateInfo']: r""" Returns a list of DelegateInfo objects from a vec_u8. """ json = json_from_vec_u8(vec_u8) + if json is None: + return [] + return [DelegateInfo.from_json(delegate) for delegate in json] @classmethod @@ -280,10 +295,13 @@ class SubnetInfo: emission_value: float @classmethod - def from_vec_u8(cls, vec_u8: List[int]) -> 'SubnetInfo': + def from_vec_u8(cls, vec_u8: List[int]) -> Optional['SubnetInfo']: r""" Returns a SubnetInfo object from a vec_u8. """ json = json_from_vec_u8(vec_u8) + if json is None: + return None + return SubnetInfo.from_json(json) @classmethod @@ -291,6 +309,9 @@ def list_from_vec_u8(cls, vec_u8: List[int]) -> List['SubnetInfo']: r""" Returns a list of SubnetInfo objects from a vec_u8. """ json = json_from_vec_u8(vec_u8) + if json is None: + return [] + return [SubnetInfo.from_json(subnet) for subnet in json] @classmethod From f6ac445be001135e4d0c2a3ca4538fc0aeec3415 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Mon, 13 Mar 2023 16:14:58 -0400 Subject: [PATCH 3/4] use cleaner none/[] check --- bittensor/_subtensor/subtensor_impl.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/bittensor/_subtensor/subtensor_impl.py b/bittensor/_subtensor/subtensor_impl.py index 82546e5a80..bf856b4990 100644 --- a/bittensor/_subtensor/subtensor_impl.py +++ b/bittensor/_subtensor/subtensor_impl.py @@ -630,7 +630,7 @@ def make_substrate_call_with_retry(): json_body = make_substrate_call_with_retry() result = json_body['result'] - if result == None: + if result in (None, []): return [] return SubnetInfo.list_from_vec_u8( result ) @@ -651,7 +651,7 @@ def make_substrate_call_with_retry(): json_body = make_substrate_call_with_retry() result = json_body['result'] - if result == None: + if result in (None, []): return None return SubnetInfo.from_vec_u8( result ) @@ -690,7 +690,7 @@ def make_substrate_call_with_retry(encoded_hotkey: List[int]): json_body = make_substrate_call_with_retry(encoded_hotkey) result = json_body['result'] - if result == None: + if result in (None, []): return None return DelegateInfo.from_vec_u8( result ) @@ -710,7 +710,7 @@ def make_substrate_call_with_retry(): json_body = make_substrate_call_with_retry() result = json_body['result'] - if result == None: + if result in (None, []): return [] return DelegateInfo.list_from_vec_u8( result ) @@ -783,9 +783,12 @@ def make_substrate_call_with_retry(): params=params ) json_body = make_substrate_call_with_retry() - if json_body['result'] == None: + result = json_body['result'] + + if result in (None, []): return NeuronInfo._null_neuron() - return NeuronInfo.from_vec_u8( json_body['result'] ) + + return NeuronInfo.from_vec_u8( result ) def neurons(self, netuid: int, block: Optional[int] = None ) -> List[NeuronInfo]: r""" Returns a list of neuron from the chain. @@ -812,6 +815,9 @@ def make_substrate_call_with_retry(): json_body = make_substrate_call_with_retry() result = json_body['result'] + + if result in (None, []): + return [] return NeuronInfo.list_from_vec_u8( result ) From 0d03780a5f6ebc2fdb24cc6aa8c69e3c9c5e4026 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 14 Mar 2023 17:54:41 -0400 Subject: [PATCH 4/4] use new weight and bond format --- bittensor/_subtensor/chain_data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor/_subtensor/chain_data.py b/bittensor/_subtensor/chain_data.py index e971791db7..fd4a9bb8c4 100644 --- a/bittensor/_subtensor/chain_data.py +++ b/bittensor/_subtensor/chain_data.py @@ -109,8 +109,8 @@ def from_json(cls, json: Dict) -> 'NeuronInfo': dividends = json['dividends'] / U16_MAX, last_update = json['last_update'], validator_permit = json['validator_permit'], - weights = json['weights'], - bonds = json['bonds'], + weights = [ (uid, w) for uid, w in enumerate(json['weights']) ], + bonds = [ (uid, b) for uid, b in enumerate(json['bonds']) ], prometheus_info = PrometheusInfo.from_json(json['prometheus_info']), axon_info = AxonInfo.from_json(json['axon_info']), )