From 43efa75b9399134d7c9766385dc770c7c95eab08 Mon Sep 17 00:00:00 2001 From: dev-miro26 Date: Mon, 23 Mar 2026 14:56:27 -0400 Subject: [PATCH] Remove ProposalVoteData and associated voting functionality from AsyncSubtensor and Subtensor classes, along with related tests and imports, to clean up deprecated code. --- bittensor/core/async_subtensor.py | 43 +--- bittensor/core/chain_data/__init__.py | 2 - .../core/chain_data/proposal_vote_data.py | 27 --- bittensor/core/subtensor.py | 35 +-- bittensor/extras/subtensor_api/chain.py | 1 - bittensor/utils/easy_imports.py | 4 +- tests/e2e_tests/test_delegate.py | 214 ------------------ tests/e2e_tests/utils/__init__.py | 89 -------- tests/unit_tests/test_async_subtensor.py | 89 -------- 9 files changed, 4 insertions(+), 500 deletions(-) delete mode 100644 bittensor/core/chain_data/proposal_vote_data.py diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index d199c029fc..e193574825 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -25,7 +25,7 @@ MetagraphInfo, NeuronInfo, NeuronInfoLite, - ProposalVoteData, + ProxyAnnouncementInfo, ProxyConstants, ProxyInfo, @@ -4956,47 +4956,6 @@ async def get_unstake_fee( ) return sim_swap_result.alpha_fee.set_unit(netuid=netuid) - async def get_vote_data( - self, - proposal_hash: str, - block: Optional[int] = None, - block_hash: Optional[str] = None, - reuse_block: bool = False, - ) -> Optional["ProposalVoteData"]: - # TODO: is this all deprecated? Didn't subtensor senate stuff get removed? - """ - Retrieves the voting data for a specific proposal on the Bittensor blockchain. This data includes information - about how senate members have voted on the proposal. - - Parameters: - proposal_hash: The hash of the proposal for which voting data is requested. - block: The blockchain block number for the query. - block_hash: The hash of the blockchain block number to query the voting data. - reuse_block: Whether to reuse the last-used blockchain block hash. - - Returns: - An object containing the proposal's voting data, or `None` if not found. - - This function is important for tracking and understanding the decision-making processes within the Bittensor - network, particularly how proposals are received and acted upon by the governing body. - """ - block_hash = await self.determine_block_hash(block, block_hash, reuse_block) - vote_data = cast( - Optional[dict[str, Any]], - await self.substrate.query( - module="Triumvirate", - storage_function="Voting", - params=[proposal_hash], - block_hash=block_hash, - reuse_block_hash=reuse_block, - ), - ) - - if vote_data is None: - return None - - return ProposalVoteData.from_dict(vote_data) - async def get_uid_for_hotkey_on_subnet( self, hotkey_ss58: str, diff --git a/bittensor/core/chain_data/__init__.py b/bittensor/core/chain_data/__init__.py index 0982c5cde2..69bc07b73f 100644 --- a/bittensor/core/chain_data/__init__.py +++ b/bittensor/core/chain_data/__init__.py @@ -27,7 +27,6 @@ from .neuron_info import NeuronInfo from .neuron_info_lite import NeuronInfoLite from .prometheus_info import PrometheusInfo -from .proposal_vote_data import ProposalVoteData from .proxy import ProxyAnnouncementInfo, ProxyConstants, ProxyInfo, ProxyType from .root_claim import RootClaimType from .scheduled_coldkey_swap_info import ScheduledColdkeySwapInfo @@ -63,7 +62,6 @@ "NeuronInfoLite", "PrometheusInfo", "ProposalCallData", - "ProposalVoteData", "ProxyConstants", "ProxyAnnouncementInfo", "ProxyInfo", diff --git a/bittensor/core/chain_data/proposal_vote_data.py b/bittensor/core/chain_data/proposal_vote_data.py deleted file mode 100644 index 3cf5439955..0000000000 --- a/bittensor/core/chain_data/proposal_vote_data.py +++ /dev/null @@ -1,27 +0,0 @@ -from dataclasses import dataclass - -from bittensor.core.chain_data.info_base import InfoBase -from bittensor.core.chain_data.utils import decode_account_id - - -@dataclass -class ProposalVoteData(InfoBase): - """ - Senate / Proposal data - """ - - index: int - threshold: int - ayes: list[str] - nays: list[str] - end: int - - @classmethod - def from_dict(cls, proposal_dict: dict) -> "ProposalVoteData": - return cls( - ayes=[decode_account_id(key) for key in proposal_dict["ayes"]], - end=proposal_dict["end"], - index=proposal_dict["index"], - nays=[decode_account_id(key) for key in proposal_dict["nays"]], - threshold=proposal_dict["threshold"], - ) diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 53f594e4f8..5a39bf803b 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -25,7 +25,7 @@ MetagraphInfo, NeuronInfo, NeuronInfoLite, - ProposalVoteData, + ProxyAnnouncementInfo, ProxyConstants, ProxyInfo, @@ -4044,39 +4044,6 @@ def get_unstake_fee( ) return sim_swap_result.alpha_fee.set_unit(netuid=netuid) - def get_vote_data( - self, proposal_hash: str, block: Optional[int] = None - ) -> Optional["ProposalVoteData"]: - # TODO: is this all deprecated? Didn't subtensor senate stuff get removed? - """ - Retrieves the voting data for a specific proposal on the Bittensor blockchain. This data includes information - about how senate members have voted on the proposal. - - Parameters: - proposal_hash: The hash of the proposal for which voting data is requested. - block: The blockchain block number for the query. If `None`, queries the current chain head. - - Returns: - An object containing the proposal's voting data, or `None` if not found. - - This function is important for tracking and understanding the decision-making processes within the Bittensor - network, particularly how proposals are received and acted upon by the governing body. - """ - vote_data = cast( - Optional[dict[str, Any]], - self.substrate.query( - module="Triumvirate", - storage_function="Voting", - params=[proposal_hash], - block_hash=self.determine_block_hash(block), - ), - ) - - if vote_data is None: - return None - - return ProposalVoteData.from_dict(vote_data) - def get_uid_for_hotkey_on_subnet( self, hotkey_ss58: str, netuid: int, block: Optional[int] = None ) -> Optional[int]: diff --git a/bittensor/extras/subtensor_api/chain.py b/bittensor/extras/subtensor_api/chain.py index 4cca40bfd1..3261903a25 100644 --- a/bittensor/extras/subtensor_api/chain.py +++ b/bittensor/extras/subtensor_api/chain.py @@ -16,7 +16,6 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]): self.get_minimum_required_stake = subtensor.get_minimum_required_stake self.get_start_call_delay = subtensor.get_start_call_delay self.get_timestamp = subtensor.get_timestamp - self.get_vote_data = subtensor.get_vote_data self.is_fast_blocks = subtensor.is_fast_blocks self.is_in_admin_freeze_window = subtensor.is_in_admin_freeze_window self.last_drand_round = subtensor.last_drand_round diff --git a/bittensor/utils/easy_imports.py b/bittensor/utils/easy_imports.py index f31d968a79..af33578351 100644 --- a/bittensor/utils/easy_imports.py +++ b/bittensor/utils/easy_imports.py @@ -53,7 +53,7 @@ ProxyType, PrometheusInfo, ProposalCallData, - ProposalVoteData, + ScheduledColdkeySwapInfo, SelectiveMetagraphIndex, StakeInfo, @@ -167,7 +167,7 @@ "NeuronInfoLite", "PrometheusInfo", "ProposalCallData", - "ProposalVoteData", + "ScheduledColdkeySwapInfo", "SelectiveMetagraphIndex", "StakeInfo", diff --git a/tests/e2e_tests/test_delegate.py b/tests/e2e_tests/test_delegate.py index d0a4a6fb95..0fb5f4d6dc 100644 --- a/tests/e2e_tests/test_delegate.py +++ b/tests/e2e_tests/test_delegate.py @@ -2,7 +2,6 @@ from bittensor.core.chain_data.chain_identity import ChainIdentity from bittensor.core.chain_data.delegate_info import DelegatedInfo, DelegateInfo -from bittensor.core.chain_data.proposal_vote_data import ProposalVoteData from bittensor.core.errors import ( DelegateTakeTooHigh, DelegateTxRateLimitExceeded, @@ -11,13 +10,9 @@ ) from bittensor.utils.balance import Balance from tests.e2e_tests.utils import ( - async_propose, async_set_identity, - async_vote, get_dynamic_balance, - propose, set_identity, - vote, TestSubnet, AdminUtils, ACTIVATE_SUBNET, @@ -710,212 +705,3 @@ async def test_nominator_min_required_stake_async( netuid=alice_sn.netuid, ) assert stake == Balance.from_tao(0, alice_sn.netuid) - - -# Read https://github.com/opentensor/bittensor/pull/3102 -# def test_get_vote_data(subtensor, alice_wallet): -# """ -# Tests: -# - Sends Propose -# - Checks existing Proposals -# - Votes -# - Checks Proposal is updated -# """ -# assert subtensor.extrinsics.root_register(alice_wallet).success, ( -# "Can not register Alice in root SN." -# ) -# -# proposals = subtensor.queries.query_map( -# "Triumvirate", -# "ProposalOf", -# params=[], -# ) -# -# assert proposals.records == [] -# -# success, message = propose( -# subtensor=subtensor, -# wallet=alice_wallet, -# proposal=subtensor.compose_call( -# call_module="Triumvirate", -# call_function="set_members", -# call_params={ -# "new_members": [], -# "prime": None, -# "old_count": 0, -# }, -# ), -# duration=1_000_000, -# ) -# -# assert success is True, message -# assert message == "Success" -# -# proposals = subtensor.queries.query_map( -# module="Triumvirate", -# name="ProposalOf", -# params=[], -# ) -# proposals = { -# bytes(proposal_hash[0]): proposal.value for proposal_hash, proposal in proposals -# } -# -# assert list(proposals.values()) == [ -# { -# "Triumvirate": ( -# { -# "set_members": { -# "new_members": (), -# "prime": None, -# "old_count": 0, -# }, -# }, -# ), -# }, -# ] -# -# proposal_hash = list(proposals.keys())[0] -# proposal_hash = f"0x{proposal_hash.hex()}" -# -# proposal = subtensor.chain.get_vote_data( -# proposal_hash, -# ) -# -# assert proposal == ProposalVoteData( -# ayes=[], -# end=CloseInValue(1_000_000, subtensor.block), -# index=0, -# nays=[], -# threshold=3, -# ) -# -# success, message = vote( -# subtensor=subtensor, -# wallet=alice_wallet, -# hotkey=alice_wallet.hotkey.ss58_address, -# proposal=proposal_hash, -# index=0, -# approve=True, -# ) -# -# assert success is True, message -# assert message == "Success" -# -# proposal = subtensor.chain.get_vote_data( -# proposal_hash=proposal_hash, -# ) -# -# assert proposal == ProposalVoteData( -# ayes=[ -# alice_wallet.hotkey.ss58_address, -# ], -# end=CloseInValue(1_000_000, subtensor.block), -# index=0, -# nays=[], -# threshold=3, -# ) -# -# -# @pytest.mark.asyncio -# async def test_get_vote_data_async(async_subtensor, alice_wallet): -# """ -# Async tests: -# - Sends Propose -# - Checks existing Proposals -# - Votes -# - Checks Proposal is updated -# """ -# assert (await async_subtensor.extrinsics.root_register(alice_wallet)).success, ( -# "Can not register Alice in root SN." -# ) -# -# proposals = await async_subtensor.queries.query_map( -# "Triumvirate", -# "ProposalOf", -# params=[], -# ) -# -# assert proposals.records == [] -# -# success, message = await async_propose( -# subtensor=async_subtensor, -# wallet=alice_wallet, -# proposal=await async_subtensor.compose_call( -# call_module="Triumvirate", -# call_function="set_members", -# call_params={ -# "new_members": [], -# "prime": None, -# "old_count": 0, -# }, -# ), -# duration=1_000_000, -# ) -# -# assert success is True -# assert message == "Success" -# -# proposals = await async_subtensor.queries.query_map( -# module="Triumvirate", -# name="ProposalOf", -# params=[], -# ) -# proposals = { -# bytes(proposal_hash[0]): proposal.value -# async for proposal_hash, proposal in proposals -# } -# -# assert list(proposals.values()) == [ -# { -# "Triumvirate": ( -# { -# "set_members": { -# "new_members": (), -# "prime": None, -# "old_count": 0, -# }, -# }, -# ), -# }, -# ] -# -# proposal_hash = list(proposals.keys())[0] -# proposal_hash = f"0x{proposal_hash.hex()}" -# -# proposal = await async_subtensor.chain.get_vote_data( -# proposal_hash, -# ) -# -# assert proposal == ProposalVoteData( -# ayes=[], -# end=CloseInValue(1_000_000, await async_subtensor.block), -# index=0, -# nays=[], -# threshold=3, -# ) -# -# success, message = await async_vote( -# subtensor=async_subtensor, -# wallet=alice_wallet, -# hotkey=alice_wallet.hotkey.ss58_address, -# proposal=proposal_hash, -# index=0, -# approve=True, -# ) -# -# assert success is True, message -# assert message == "Success" -# -# proposal = await async_subtensor.chain.get_vote_data( -# proposal_hash=proposal_hash, -# ) -# -# assert proposal == ProposalVoteData( -# ayes=[ -# alice_wallet.hotkey.ss58_address, -# ], -# end=CloseInValue(1_000_000, await async_subtensor.block), -# index=0, -# nays=[], -# threshold=3, -# ) diff --git a/tests/e2e_tests/utils/__init__.py b/tests/e2e_tests/utils/__init__.py index 7ebb460fc7..49273648a9 100644 --- a/tests/e2e_tests/utils/__init__.py +++ b/tests/e2e_tests/utils/__init__.py @@ -123,92 +123,3 @@ async def async_set_identity( wait_for_inclusion=True, wait_for_finalization=True, ) - - -def propose(subtensor, wallet, proposal, duration): - return subtensor.sign_and_send_extrinsic( - call=subtensor.compose_call( - call_module="Triumvirate", - call_function="propose", - call_params={ - "proposal": proposal, - "length_bound": len(proposal.data), - "duration": duration, - }, - ), - wallet=wallet, - wait_for_finalization=True, - wait_for_inclusion=True, - ) - - -async def async_propose( - subtensor: "SubtensorApi", - wallet: "Wallet", - proposal, - duration, -): - return await subtensor.sign_and_send_extrinsic( - call=await subtensor.compose_call( - call_module="Triumvirate", - call_function="propose", - call_params={ - "proposal": proposal, - "length_bound": len(proposal.data), - "duration": duration, - }, - ), - wallet=wallet, - wait_for_finalization=True, - wait_for_inclusion=True, - ) - - -def vote( - subtensor: "SubtensorApi", - wallet: "Wallet", - hotkey, - proposal, - index, - approve, -): - return subtensor.sign_and_send_extrinsic( - call=subtensor.compose_call( - call_module="SubtensorModule", - call_function="vote", - call_params={ - "approve": approve, - "hotkey": hotkey, - "index": index, - "proposal": proposal, - }, - ), - wallet=wallet, - wait_for_inclusion=True, - wait_for_finalization=True, - ) - - -async def async_vote( - subtensor: "SubtensorApi", - wallet: "Wallet", - hotkey, - proposal, - index, - approve, -): - return await subtensor.sign_and_send_extrinsic( - call=await subtensor.compose_call( - call_module="SubtensorModule", - call_function="vote", - call_params={ - "approve": approve, - "hotkey": hotkey, - "index": index, - "proposal": proposal, - }, - ), - wallet=wallet, - wait_for_inclusion=True, - wait_for_finalization=True, - ) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 072be4b650..10c9a0485e 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -14,7 +14,6 @@ NeuronInfo, SelectiveMetagraphIndex, StakeInfo, - proposal_vote_data, ) from bittensor.core.errors import BalanceTypeError from bittensor.core.settings import DEFAULT_MEV_PROTECTION, DEFAULT_PERIOD @@ -39,34 +38,6 @@ def subtensor(mock_substrate): return async_subtensor.AsyncSubtensor() -def test_decode_ss58_tuples_in_proposal_vote_data(mocker): - """Tests that ProposalVoteData instance instantiation works properly,""" - # Preps - mocked_decode_account_id = mocker.patch.object( - proposal_vote_data, "decode_account_id" - ) - fake_proposal_dict = { - "index": "0", - "threshold": 1, - "ayes": ("0 line", "1 line"), - "nays": ("2 line", "3 line"), - "end": 123, - } - - # Call - async_subtensor.ProposalVoteData.from_dict(fake_proposal_dict) - - # Asserts - assert mocked_decode_account_id.call_count == len(fake_proposal_dict["ayes"]) + len( - fake_proposal_dict["nays"] - ) - assert mocked_decode_account_id.mock_calls == [ - mocker.call("0 line"), - mocker.call("1 line"), - mocker.call("2 line"), - mocker.call("3 line"), - ] - def test_decode_hex_identity_dict_with_non_tuple_value(): """Tests _decode_hex_identity_dict when value is not a tuple.""" @@ -2168,66 +2139,6 @@ async def test_get_subnet_hyperparameters_without_0x_prefix(subtensor, mocker): assert result == mocked_from_dict.return_value -@pytest.mark.asyncio -async def test_get_vote_data_success(subtensor, mocker): - """Tests get_vote_data when voting data is successfully retrieved.""" - # Preps - fake_proposal_hash = "valid_proposal_hash" - fake_block_hash = "block_hash" - fake_vote_data = {"ayes": ["senate_member_1"], "nays": ["senate_member_2"]} - - mocked_query = mocker.AsyncMock(return_value=fake_vote_data) - subtensor.substrate.query = mocked_query - - mocked_proposal_vote_data = mocker.Mock() - mocker.patch.object( - async_subtensor.ProposalVoteData, - "from_dict", - return_value=mocked_proposal_vote_data, - ) - - # Call - result = await subtensor.get_vote_data( - proposal_hash=fake_proposal_hash, block_hash=fake_block_hash - ) - - # Asserts - mocked_query.assert_called_once_with( - module="Triumvirate", - storage_function="Voting", - params=[fake_proposal_hash], - block_hash=fake_block_hash, - reuse_block_hash=False, - ) - assert result == mocked_proposal_vote_data - - -@pytest.mark.asyncio -async def test_get_vote_data_no_data(subtensor, mocker): - """Tests get_vote_data when no voting data is available.""" - # Preps - fake_proposal_hash = "invalid_proposal_hash" - fake_block_hash = "block_hash" - - mocked_query = mocker.AsyncMock(return_value=None) - subtensor.substrate.query = mocked_query - - # Call - result = await subtensor.get_vote_data( - proposal_hash=fake_proposal_hash, block_hash=fake_block_hash - ) - - # Asserts - mocked_query.assert_called_once_with( - module="Triumvirate", - storage_function="Voting", - params=[fake_proposal_hash], - block_hash=fake_block_hash, - reuse_block_hash=False, - ) - assert result is None - - @pytest.mark.asyncio async def test_get_delegate_identities(subtensor, mocker): """Tests get_delegate_identities with successful data retrieval from both chain and GitHub."""