diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index c2d38fcad3..926c593ac0 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -26,6 +26,7 @@ decode_account_id, DynamicInfo, ) +from bittensor.core.chain_data.utils import decode_metadata from bittensor.core.config import Config from bittensor.core.errors import SubstrateRequestException from bittensor.core.extrinsics.asyncex.commit_reveal import commit_reveal_v3_extrinsic @@ -342,7 +343,7 @@ async def query_map( block_hash=block_hash, reuse_block_hash=reuse_block, ) - return getattr(result, "value", None) + return result async def query_map_subtensor( self, @@ -927,7 +928,12 @@ async def get_children( return False, [], format_error_message(e) async def get_commitment( - self, netuid: int, uid: int, block: Optional[int] = None + self, + netuid: int, + uid: int, + block: Optional[int] = None, + block_hash: Optional[str] = None, + reuse_block: bool = False, ) -> str: """ Retrieves the on-chain commitment for a specific neuron in the Bittensor network. @@ -937,6 +943,8 @@ async def get_commitment( uid (int): The unique identifier of the neuron. block (Optional[int]): The block number to retrieve the commitment from. If None, the latest block is used. Default is ``None``. + block_hash (Optional[str]): The hash of the block to retrieve the subnet unique identifiers from. + reuse_block (bool): Whether to reuse the last-used block hash. Returns: str: The commitment data as a string. @@ -950,15 +958,47 @@ async def get_commitment( ) return "" - metadata = await get_metadata(self, netuid, hotkey, block) + metadata = await get_metadata( + self, netuid, hotkey, block, block_hash, reuse_block + ) try: - commitment = metadata["info"]["fields"][0][0] # type: ignore - bytes_tuple = commitment[next(iter(commitment.keys()))][0] # type: ignore - return bytes(bytes_tuple).decode() - + return decode_metadata(metadata) except TypeError: return "" + async def get_all_commitments( + self, + netuid: int, + block: Optional[int] = None, + block_hash: Optional[str] = None, + reuse_block: bool = False, + ) -> dict[str, str]: + """ + Retrieves the on-chain commitments for a specific subnet in the Bittensor network. + + Arguments: + netuid (int): The unique identifier of the subnetwork. + block (Optional[int]): The block number to retrieve the commitment from. If None, the latest block is used. + Default is ``None``. + block_hash (Optional[str]): The hash of the block to retrieve the subnet unique identifiers from. + reuse_block (bool): Whether to reuse the last-used block hash. + + Returns: + dict[str, str]: A mapping of the ss58:commitment with the commitment as a string + """ + query = await self.query_map( + module="Commitments", + name="CommitmentOf", + params=[netuid], + block=block, + block_hash=block_hash, + reuse_block=reuse_block, + ) + result = {} + async for id_, value in query: + result[decode_account_id(id_[0])] = decode_account_id(value) + return result + async def get_current_weight_commit_info( self, netuid: int, diff --git a/bittensor/core/chain_data/utils.py b/bittensor/core/chain_data/utils.py index bbd0e6c9ed..c7d6986038 100644 --- a/bittensor/core/chain_data/utils.py +++ b/bittensor/core/chain_data/utils.py @@ -129,3 +129,9 @@ def process_stake_data(stake_data: list) -> dict: account_id = decode_account_id(account_id_bytes) decoded_stake_data.update({account_id: Balance.from_rao(stake_)}) return decoded_stake_data + + +def decode_metadata(metadata: dict) -> str: + commitment = metadata["info"]["fields"][0][0] + bytes_tuple = commitment[next(iter(commitment.keys()))][0] + return bytes(bytes_tuple).decode() diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 9b49740068..690af504b7 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -24,6 +24,7 @@ SubnetInfo, decode_account_id, ) +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 from bittensor.core.extrinsics.commit_weights import ( @@ -210,7 +211,7 @@ def query_map( params=params, block_hash=self.determine_block_hash(block=block), ) - return getattr(result, "value", None) + return result def query_map_subtensor( self, name: str, block: Optional[int] = None, params: Optional[list] = None @@ -731,15 +732,27 @@ def get_commitment(self, netuid: int, uid: int, block: Optional[int] = None) -> ) return "" - metadata = get_metadata(self, netuid, hotkey, block) + metadata = cast(dict, get_metadata(self, netuid, hotkey, block)) try: - commitment = metadata["info"]["fields"][0][0] # type: ignore - bytes_tuple = commitment[next(iter(commitment.keys()))][0] # type: ignore - return bytes(bytes_tuple).decode() + return decode_metadata(metadata) except TypeError: return "" + def get_all_commitments( + self, netuid: int, block: Optional[int] = None + ) -> dict[str, str]: + query = self.query_map( + module="Commitments", + name="CommitmentOf", + params=[netuid], + block=block, + ) + result = {} + for id_, value in query: + result[decode_account_id(id_[0])] = decode_account_id(value) + return result + def get_current_weight_commit_info( self, netuid: int, block: Optional[int] = None ) -> list: diff --git a/tests/unit_tests/test_subtensor.py b/tests/unit_tests/test_subtensor.py index d7ec8d9b35..c11ac36956 100644 --- a/tests/unit_tests/test_subtensor.py +++ b/tests/unit_tests/test_subtensor.py @@ -1000,7 +1000,7 @@ def test_query_map(subtensor, mocker): params=None, block_hash=None, ) - assert result == subtensor.substrate.query_map.return_value.value + assert result == subtensor.substrate.query_map.return_value def test_query_constant(subtensor, mocker): @@ -1682,8 +1682,10 @@ def test_get_commitment(subtensor, mocker): fake_uid = 2 fake_block = 3 fake_hotkey = "hotkey" - fake_hex_data = "0x010203" - expected_result = bytes.fromhex(fake_hex_data[2:]).decode() + expected_result = ( + "{'peer_id': '12D3KooWFWnHBmUFxvfL6PfZ5eGHdhgsEqNnsxuN1HE9EtfW8THi', " + "'model_huggingface_id': 'kmfoda/gpt2-1b-miner-3'}" + ) mocked_metagraph = mocker.MagicMock() subtensor.metagraph = mocked_metagraph @@ -1691,7 +1693,137 @@ def test_get_commitment(subtensor, mocker): mocked_get_metadata = mocker.patch.object(subtensor_module, "get_metadata") mocked_get_metadata.return_value = { - "info": {"fields": [{fake_hex_data: fake_hex_data}]} + "deposit": 0, + "block": 3843930, + "info": { + "fields": ( + ( + { + "Raw117": ( + ( + 123, + 39, + 112, + 101, + 101, + 114, + 95, + 105, + 100, + 39, + 58, + 32, + 39, + 49, + 50, + 68, + 51, + 75, + 111, + 111, + 87, + 70, + 87, + 110, + 72, + 66, + 109, + 85, + 70, + 120, + 118, + 102, + 76, + 54, + 80, + 102, + 90, + 53, + 101, + 71, + 72, + 100, + 104, + 103, + 115, + 69, + 113, + 78, + 110, + 115, + 120, + 117, + 78, + 49, + 72, + 69, + 57, + 69, + 116, + 102, + 87, + 56, + 84, + 72, + 105, + 39, + 44, + 32, + 39, + 109, + 111, + 100, + 101, + 108, + 95, + 104, + 117, + 103, + 103, + 105, + 110, + 103, + 102, + 97, + 99, + 101, + 95, + 105, + 100, + 39, + 58, + 32, + 39, + 107, + 109, + 102, + 111, + 100, + 97, + 47, + 103, + 112, + 116, + 50, + 45, + 49, + 98, + 45, + 109, + 105, + 110, + 101, + 114, + 45, + 51, + 39, + 125, + ), + ) + }, + ), + ) + }, } # Call