From fbe4c387aac66066bab378e2a44c07d145173242 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Sep 2025 16:40:28 -0700 Subject: [PATCH 1/7] reliability --- bittensor/core/chain_data/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bittensor/core/chain_data/utils.py b/bittensor/core/chain_data/utils.py index b1a81ce517..e2b69dadf2 100644 --- a/bittensor/core/chain_data/utils.py +++ b/bittensor/core/chain_data/utils.py @@ -137,9 +137,9 @@ def process_stake_data(stake_data: list) -> dict: def decode_metadata(metadata: dict) -> str: commitment = metadata["info"]["fields"][0][0] - bytes_tuple_ = commitment[next(iter(commitment.keys()))] - bytes_tuple = bytes_tuple_[0] if len(bytes_tuple_) > 0 else bytes_tuple_ - return bytes(bytes_tuple).decode() + raw_bytes = next(iter(commitment.values())) + byte_tuple = raw_bytes[0] if raw_bytes else raw_bytes + return bytes(byte_tuple).decode("utf-8", errors="ignore") def decode_block(data: bytes) -> int: @@ -168,6 +168,7 @@ def decode_revealed_commitment(encoded_data) -> tuple[int, str]: def scale_decode_offset(data: bytes) -> int: """Decodes the scale offset from a given byte data sequence.""" + print(">>> data", data) first_byte = data[0] mode = first_byte & 0b11 if mode == 0: From a190989125546cf507a9565eed9807a5384ef433 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Sep 2025 16:43:35 -0700 Subject: [PATCH 2/7] update `MetagraphInfo` and `SelectiveMetagraphIndex` --- bittensor/core/chain_data/metagraph_info.py | 27 +++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/bittensor/core/chain_data/metagraph_info.py b/bittensor/core/chain_data/metagraph_info.py index cc329a84ad..7aee25f5c7 100644 --- a/bittensor/core/chain_data/metagraph_info.py +++ b/bittensor/core/chain_data/metagraph_info.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from typing import Optional, Union - from bittensor.core import settings from bittensor.core.chain_data.axon_info import AxonInfo from bittensor.core.chain_data.chain_identity import ChainIdentity @@ -13,6 +12,26 @@ from bittensor.utils.balance import Balance, fixed_to_float +SELECTIVE_METAGRAPH_COMMITMENTS_OFFSET = 14 + + +def get_selective_metagraph_commitments( + decoded: dict, +) -> Optional[tuple[tuple[str, str]]]: + """Returns a tuple of hotkeys and commitments from decoded chain data if provided, else None.""" + if commitments := decoded.get("commitments"): + result = [] + for commitment in commitments: + account_id_bytes, commitment_bytes = commitment + hotkey = decode_account_id(account_id_bytes) + commitment = bytes( + commitment_bytes[SELECTIVE_METAGRAPH_COMMITMENTS_OFFSET:] + ).decode("utf-8", errors="ignore") + result.append((hotkey, commitment)) + return tuple(result) + return None + + # to balance with unit (shortcut) def _tbwu(val: Optional[int], netuid: Optional[int] = 0) -> Optional[Balance]: """Returns a Balance object from a value and unit.""" @@ -147,7 +166,9 @@ class MetagraphInfo(InfoBase): ] # List of dividend payout in alpha via subnet. # List of validators - validators: list[str] + validators: Optional[list[str]] + + commitments: Optional[tuple[tuple[str, str]]] @classmethod def _from_dict(cls, decoded: dict) -> "MetagraphInfo": @@ -375,6 +396,7 @@ def _from_dict(cls, decoded: dict) -> "MetagraphInfo": validators=[v for v in decoded["validators"]] if decoded.get("validators") is not None else None, + commitments=get_selective_metagraph_commitments(decoded), ) @@ -508,6 +530,7 @@ class SelectiveMetagraphIndex(Enum): TaoDividendsPerHotkey = 70 AlphaDividendsPerHotkey = 71 Validators = 72 + Commitments = 73 @staticmethod def all_indices() -> list[int]: From 9e33a10bfd2272c29dd6cb051cb5244aecf81298 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Sep 2025 16:43:52 -0700 Subject: [PATCH 3/7] add an error logging message --- bittensor/core/async_subtensor.py | 10 ++++++++-- bittensor/core/subtensor.py | 11 ++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index 67591b6c30..e40d8752c6 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -1538,7 +1538,8 @@ async def get_commitment( ) try: return decode_metadata(metadata) - except TypeError: + except Exception as error: + logging.error(error) return "" async def get_last_commitment_bonds_reset_block( @@ -1609,7 +1610,12 @@ async def get_all_commitments( ) result = {} async for id_, value in query: - result[decode_account_id(id_[0])] = decode_metadata(value.value) + try: + result[decode_account_id(id_[0])] = decode_metadata(value) + except Exception as error: + logging.error( + f"Error decoding [red]{id_}[/red] and [red]{value}[/red]: {error}" + ) return result async def get_revealed_commitment_by_hotkey( diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 257ede8b60..f01f9cb790 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -956,8 +956,8 @@ def get_commitment(self, netuid: int, uid: int, block: Optional[int] = None) -> metadata = cast(dict, get_metadata(self, netuid, hotkey, block)) try: return decode_metadata(metadata) - - except TypeError: + except Exception as error: + logging.error(error) return "" def get_last_commitment_bonds_reset_block( @@ -998,7 +998,12 @@ def get_all_commitments( ) result = {} for id_, value in query: - result[decode_account_id(id_[0])] = decode_metadata(value) + try: + result[decode_account_id(id_[0])] = decode_metadata(value) + except Exception as error: + logging.error( + f"Error decoding [red]{id_}[/red] and [red]{value}[/red]: {error}" + ) return result def get_revealed_commitment_by_hotkey( From 9f3ae2954c56bca0dcea8f78ef9daa7cca5e9c16 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Sep 2025 16:44:00 -0700 Subject: [PATCH 4/7] update tests --- tests/e2e_tests/test_metagraph.py | 4 ++++ tests/unit_tests/test_async_subtensor.py | 2 +- tests/unit_tests/test_subtensor.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/e2e_tests/test_metagraph.py b/tests/e2e_tests/test_metagraph.py index 0e2fc4723c..bcecfa2e5c 100644 --- a/tests/e2e_tests/test_metagraph.py +++ b/tests/e2e_tests/test_metagraph.py @@ -290,6 +290,7 @@ def test_metagraph_info(subtensor, alice_wallet, bob_wallet): ("5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM", Balance(0).set_unit(1)) ], validators=None, + commitments=None, ) assert metagraph_info == expected_metagraph_info @@ -371,6 +372,7 @@ def test_metagraph_info(subtensor, alice_wallet, bob_wallet): tao_dividends_per_hotkey=[], alpha_dividends_per_hotkey=[], validators=None, + commitments=None, ), metagraph_info, ] @@ -552,6 +554,7 @@ def test_metagraph_info_with_indexes(subtensor, alice_wallet, bob_wallet): tao_dividends_per_hotkey=None, alpha_dividends_per_hotkey=None, validators=None, + commitments=None, ) assert wait_to_start_call(subtensor, alice_wallet, alice_subnet_netuid) @@ -670,6 +673,7 @@ def test_metagraph_info_with_indexes(subtensor, alice_wallet, bob_wallet): tao_dividends_per_hotkey=None, alpha_dividends_per_hotkey=None, validators=None, + commitments=None, ) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index e1bf1420dd..c6617427e9 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -3174,7 +3174,7 @@ async def test_get_metagraph_info_all_fields(subtensor, mocker): # Call result = await subtensor.get_metagraph_info( - netuid=netuid, field_indices=[f for f in range(73)] + netuid=netuid, field_indices=[f for f in range(len(SelectiveMetagraphIndex))] ) # Asserts diff --git a/tests/unit_tests/test_subtensor.py b/tests/unit_tests/test_subtensor.py index 78d9ffeaa9..025b6a9b18 100644 --- a/tests/unit_tests/test_subtensor.py +++ b/tests/unit_tests/test_subtensor.py @@ -3363,7 +3363,7 @@ def test_get_metagraph_info_all_fields(subtensor, mocker): # Call result = subtensor.get_metagraph_info( - netuid=netuid, field_indices=[f for f in range(73)] + netuid=netuid, field_indices=[f for f in range(len(SelectiveMetagraphIndex))] ) # Asserts From 3900a2803f0e178780316d406e0084e90989c2f5 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Sep 2025 20:13:17 -0700 Subject: [PATCH 5/7] fix unit tests (add reg fee) --- tests/e2e_tests/test_subtensor_functions.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/e2e_tests/test_subtensor_functions.py b/tests/e2e_tests/test_subtensor_functions.py index 6dbd9805ef..dd5e2721af 100644 --- a/tests/e2e_tests/test_subtensor_functions.py +++ b/tests/e2e_tests/test_subtensor_functions.py @@ -1,7 +1,8 @@ import asyncio +import time import pytest - +from bittensor.core.extrinsics.utils import get_extrinsic_fee from bittensor.utils.balance import Balance from tests.e2e_tests.utils.chain_interactions import ( wait_epoch, @@ -67,6 +68,17 @@ async def test_subtensor_extrinsics(subtensor, templates, alice_wallet, bob_wall "Unable to register the subnet" ) + # TODO: in SDKv10 replace this logic with using `ExtrinsicResponse.extrinsic_fee` + call = subtensor.substrate.compose_call( + call_module="SubtensorModule", + call_function="register_network", + call_params={ + "hotkey": alice_wallet.hotkey.ss58_address, + "mechid": 1, + }, + ) + register_fee = get_extrinsic_fee(call, alice_wallet.hotkey, subtensor) + # Subnet burn cost is increased immediately after a subnet is registered post_subnet_creation_cost = subtensor.get_subnet_burn_cost() @@ -77,7 +89,7 @@ async def test_subtensor_extrinsics(subtensor, templates, alice_wallet, bob_wall # Assert amount is deducted once a subnetwork is registered by Alice alice_balance_post_sn = subtensor.get_balance(alice_wallet.coldkeypub.ss58_address) - assert alice_balance_post_sn + pre_subnet_creation_cost == initial_alice_balance, ( + assert alice_balance_post_sn + pre_subnet_creation_cost + register_fee == initial_alice_balance, ( "Balance is the same even after registering a subnet" ) From acdb099b10baf0c663d28b3233e6822541191663 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Sep 2025 22:46:32 -0700 Subject: [PATCH 6/7] test_incentive no flaky --- tests/e2e_tests/test_incentive.py | 28 +++++++++++++-------- tests/e2e_tests/test_subtensor_functions.py | 7 +++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/tests/e2e_tests/test_incentive.py b/tests/e2e_tests/test_incentive.py index d08fb7ece6..a727a6dbb0 100644 --- a/tests/e2e_tests/test_incentive.py +++ b/tests/e2e_tests/test_incentive.py @@ -11,7 +11,7 @@ @pytest.mark.asyncio -async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wallet): +async def test_incentive(subtensor, templates, alice_wallet, bob_wallet): """ Test the incentive mechanism and interaction of miners/validators @@ -23,21 +23,20 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa Raises: AssertionError: If any of the checks or verifications fail """ + logging.console.info("Testing [blue]test_incentive[/blue]") + alice_subnet_netuid = subtensor.subnets.get_total_subnets() # 2 # turn off admin freeze window limit for testing assert ( sudo_set_admin_utils( - local_chain, - alice_wallet, + substrate=subtensor.substrate, + wallet=alice_wallet, call_function="sudo_set_admin_freeze_window", call_params={"window": 0}, )[0] is True ), "Failed to set admin freeze window to 0" - print("Testing test_incentive") - alice_subnet_netuid = subtensor.get_total_subnets() # 2 - # Register root as Alice - the subnet owner and validator assert subtensor.register_subnet(alice_wallet, True, True), "Subnet wasn't created" @@ -48,8 +47,8 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa # Disable commit_reveal on the subnet to check proper behavior status, error = sudo_set_admin_utils( - local_chain, - alice_wallet, + substrate=subtensor.substrate, + wallet=alice_wallet, call_function="sudo_set_commit_reveal_weights_enabled", call_params={ "netuid": alice_subnet_netuid, @@ -71,7 +70,14 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa ) # Wait for the first epoch to pass - await wait_epoch(subtensor, alice_subnet_netuid) + next_epoch_start_block = subtensor.subnets.get_next_epoch_start_block( + netuid=alice_subnet_netuid + ) + subtensor.wait_for_block(next_epoch_start_block + 1) + + while subtensor.neurons(netuid=alice_subnet_netuid)[0].validator_permit is False: + await asyncio.sleep(0.25) + print(f">>> block {subtensor.block}") # Get current miner/validator stats alice_neuron = subtensor.neurons(netuid=alice_subnet_netuid)[0] @@ -93,8 +99,8 @@ async def test_incentive(local_chain, subtensor, templates, alice_wallet, bob_wa # update weights_set_rate_limit for fast-blocks tempo = subtensor.tempo(alice_subnet_netuid) status, error = sudo_set_admin_utils( - local_chain, - alice_wallet, + substrate=subtensor.substrate, + wallet=alice_wallet, call_function="sudo_set_weights_set_rate_limit", call_params={ "netuid": alice_subnet_netuid, diff --git a/tests/e2e_tests/test_subtensor_functions.py b/tests/e2e_tests/test_subtensor_functions.py index dd5e2721af..e3efb64105 100644 --- a/tests/e2e_tests/test_subtensor_functions.py +++ b/tests/e2e_tests/test_subtensor_functions.py @@ -89,9 +89,10 @@ async def test_subtensor_extrinsics(subtensor, templates, alice_wallet, bob_wall # Assert amount is deducted once a subnetwork is registered by Alice alice_balance_post_sn = subtensor.get_balance(alice_wallet.coldkeypub.ss58_address) - assert alice_balance_post_sn + pre_subnet_creation_cost + register_fee == initial_alice_balance, ( - "Balance is the same even after registering a subnet" - ) + assert ( + alice_balance_post_sn + pre_subnet_creation_cost + register_fee + == initial_alice_balance + ), "Balance is the same even after registering a subnet" # Subnet 2 is added after registration assert subtensor.get_subnets() == [0, 1, 2] From 15a7bce22c551aacb637e65e8d5a76cdfe148059 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 11 Sep 2025 01:32:59 -0700 Subject: [PATCH 7/7] remove print debug --- bittensor/core/chain_data/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bittensor/core/chain_data/utils.py b/bittensor/core/chain_data/utils.py index e2b69dadf2..2916581b1b 100644 --- a/bittensor/core/chain_data/utils.py +++ b/bittensor/core/chain_data/utils.py @@ -168,7 +168,6 @@ def decode_revealed_commitment(encoded_data) -> tuple[int, str]: def scale_decode_offset(data: bytes) -> int: """Decodes the scale offset from a given byte data sequence.""" - print(">>> data", data) first_byte = data[0] mode = first_byte & 0b11 if mode == 0: