From 3259d4bde2cb040640444c7ac592706b8faff94a Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Mon, 25 Nov 2024 19:40:56 -0500 Subject: [PATCH 1/4] add back list from vec u8 to neuron info --- bittensor/core/chain_data/neuron_info.py | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/bittensor/core/chain_data/neuron_info.py b/bittensor/core/chain_data/neuron_info.py index 478cdfa4c9..a9ae164db7 100644 --- a/bittensor/core/chain_data/neuron_info.py +++ b/bittensor/core/chain_data/neuron_info.py @@ -174,3 +174,57 @@ def from_vec_u8(cls, vec_u8: bytes) -> "NeuronInfo": ), is_null=False, ) + + @classmethod + def list_from_vec_u8(cls, vec_u8: bytes) -> list["NeuronInfo"]: + nn = bt_decode.NeuronInfo.decode_vec(bytes(vec_u8)) + + def fix(n): + stake_dict = process_stake_data(n.stake) + total_stake = sum(stake_dict.values()) if stake_dict else Balance(0) + axon_info = n.axon_info + coldkey = decode_account_id(n.coldkey) + hotkey = decode_account_id(n.hotkey) + return NeuronInfo( + hotkey=hotkey, + coldkey=coldkey, + uid=n.uid, + netuid=n.netuid, + active=n.active, + stake=total_stake, + stake_dict=stake_dict, + total_stake=total_stake, + rank=u16_normalized_float(n.rank), + emission=n.emission / 1e9, + incentive=u16_normalized_float(n.incentive), + consensus=u16_normalized_float(n.consensus), + trust=u16_normalized_float(n.trust), + validator_trust=u16_normalized_float(n.validator_trust), + dividends=u16_normalized_float(n.dividends), + last_update=n.last_update, + validator_permit=n.validator_permit, + weights=[[e[0], e[1]] for e in n.weights], + bonds=[[e[0], e[1]] for e in n.bonds], + pruning_score=n.pruning_score, + prometheus_info=PrometheusInfo( + block=n.prometheus_info.block, + version=n.prometheus_info.version, + ip=str(netaddr.IPAddress(n.prometheus_info.ip)), + port=n.prometheus_info.port, + ip_type=n.prometheus_info.ip_type, + ), + axon_info=AxonInfo( + version=axon_info.version, + ip=str(netaddr.IPAddress(axon_info.ip)), + port=axon_info.port, + ip_type=axon_info.ip_type, + placeholder1=axon_info.placeholder1, + placeholder2=axon_info.placeholder2, + protocol=axon_info.protocol, + hotkey=hotkey, + coldkey=coldkey, + ), + is_null=False, + ) + + return [fix(n) for n in nn] From c93b8b96c3ab6840e1bc172bc5f2ef577a6365f8 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Mon, 25 Nov 2024 19:43:12 -0500 Subject: [PATCH 2/4] use new decode in the neurons func --- bittensor/core/async_subtensor.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index 4c456ac83a..a8d3ac52f4 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -783,7 +783,7 @@ async def get_existential_deposit( return Balance.from_rao(result) async def neurons( - self, netuid: int, block_hash: Optional[str] = None + self, netuid: int, block_hash: Optional[str] = None, reuse_block: bool = False ) -> list[NeuronInfo]: """ Retrieves a list of all neurons within a specified subnet of the Bittensor network. @@ -792,29 +792,27 @@ async def neurons( Args: netuid (int): The unique identifier of the subnet. block_hash (str): The hash of the blockchain block number for the query. + reuse_block (bool): Whether to reuse the last-used blockchain block hash. Returns: A list of NeuronInfo objects detailing each neuron's characteristics in the subnet. Understanding the distribution and status of neurons within a subnet is key to comprehending the network's decentralized structure and the dynamics of its consensus and governance processes. """ - neurons_lite, weights, bonds = await asyncio.gather( - self.neurons_lite(netuid=netuid, block_hash=block_hash), - self.weights(netuid=netuid, block_hash=block_hash), - self.bonds(netuid=netuid, block_hash=block_hash), + hex_bytes_result = await self.query_runtime_api( + runtime_api="NeuronInfoRuntimeApi", + method="get_neurons", + params=[ + netuid + ], + block_hash=block_hash, + reuse_block=reuse_block, ) - weights_as_dict = {uid: w for uid, w in weights} - bonds_as_dict = {uid: b for uid, b in bonds} - - neurons = [ - NeuronInfo.from_weights_bonds_and_neuron_lite( - neuron_lite, weights_as_dict, bonds_as_dict - ) - for neuron_lite in neurons_lite - ] + if hex_bytes_result is None: + return [] - return neurons + return NeuronInfo.list_from_vec_u8(hex_to_bytes(hex_bytes_result)) async def neurons_lite( self, netuid: int, block_hash: Optional[str] = None, reuse_block: bool = False From 9ea26a6cb5cd13570c84737492efcf48a7a5a07e Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 26 Nov 2024 16:22:47 -0500 Subject: [PATCH 3/4] chore: ruff --- bittensor/core/async_subtensor.py | 4 +--- bittensor/core/chain_data/neuron_info.py | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index a8d3ac52f4..881b5ebab8 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -802,9 +802,7 @@ async def neurons( hex_bytes_result = await self.query_runtime_api( runtime_api="NeuronInfoRuntimeApi", method="get_neurons", - params=[ - netuid - ], + params=[netuid], block_hash=block_hash, reuse_block=reuse_block, ) diff --git a/bittensor/core/chain_data/neuron_info.py b/bittensor/core/chain_data/neuron_info.py index a9ae164db7..ecc1b2488c 100644 --- a/bittensor/core/chain_data/neuron_info.py +++ b/bittensor/core/chain_data/neuron_info.py @@ -174,7 +174,7 @@ def from_vec_u8(cls, vec_u8: bytes) -> "NeuronInfo": ), is_null=False, ) - + @classmethod def list_from_vec_u8(cls, vec_u8: bytes) -> list["NeuronInfo"]: nn = bt_decode.NeuronInfo.decode_vec(bytes(vec_u8)) @@ -226,5 +226,5 @@ def fix(n): ), is_null=False, ) - + return [fix(n) for n in nn] From 0aa02c237b2021c5d74f88daa42908fd33e779b0 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 26 Nov 2024 18:27:40 -0800 Subject: [PATCH 4/4] fix `tests/unit_tests/test_async_subtensor.py::test_neurons` --- tests/unit_tests/test_async_subtensor.py | 49 ++++++++++-------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index c09a1499c1..88595421b6 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -992,41 +992,32 @@ async def test_neurons(subtensor, mocker): # Preps fake_netuid = 1 fake_block_hash = "block_hash" - fake_neurons = [mocker.Mock(), mocker.Mock()] - fake_weights = [(1, [(10, 20), (30, 40)]), (2, [(50, 60), (70, 80)])] - fake_bonds = [(1, [(10, 20), (30, 40)]), (2, [(50, 60), (70, 80)])] - - mocked_neurons_lite = mocker.AsyncMock(return_value=fake_neurons) - subtensor.neurons_lite = mocked_neurons_lite - - mocked_weights = mocker.AsyncMock(return_value=fake_weights) - subtensor.weights = mocked_weights - - mocked_bonds = mocker.AsyncMock(return_value=fake_bonds) - subtensor.bonds = mocked_bonds + fake_reuse_block_hash = True - mocked_neuron_info_method = mocker.Mock() - async_subtensor.NeuronInfo.from_weights_bonds_and_neuron_lite = ( - mocked_neuron_info_method + mocked_query_runtime_api = mocker.patch.object( + subtensor, "query_runtime_api", return_value="NOT NONE" + ) + mocked_hex_to_bytes = mocker.patch.object(async_subtensor, "hex_to_bytes") + mocked_neuron_info_list_from_vec_u8 = mocker.patch.object( + async_subtensor.NeuronInfo, "list_from_vec_u8" ) - # Call - result = await subtensor.neurons(netuid=fake_netuid, block_hash=fake_block_hash) + result = await subtensor.neurons( + netuid=fake_netuid, + block_hash=fake_block_hash, + reuse_block=fake_reuse_block_hash, + ) # Asserts - mocked_neurons_lite.assert_awaited_once() - mocked_neurons_lite.assert_called_once_with( - netuid=fake_netuid, block_hash=fake_block_hash - ) - mocked_weights.assert_awaited_once() - mocked_weights.assert_called_once_with( - netuid=fake_netuid, block_hash=fake_block_hash + mocked_query_runtime_api.assert_called_once_with( + runtime_api="NeuronInfoRuntimeApi", + method="get_neurons", + params=[fake_netuid], + block_hash=fake_block_hash, + reuse_block=fake_reuse_block_hash, ) - mocked_bonds.assert_awaited_once() - mocked_bonds.assert_called_once_with(netuid=fake_netuid, block_hash=fake_block_hash) - assert result == [ - mocked_neuron_info_method.return_value for _ in range(len(fake_neurons)) - ] + mocked_hex_to_bytes.assert_called_once_with(mocked_query_runtime_api.return_value) + assert result == mocked_neuron_info_list_from_vec_u8.return_value @pytest.mark.parametrize(