diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index 7eff4115f2..894a6310ae 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -2748,6 +2748,45 @@ async def get_subnet_prices( prices.update({0: Balance.from_tao(1)}) return prices + async def get_timelocked_weight_commits( + self, + netuid: int, + block: Optional[int] = None, + block_hash: Optional[str] = None, + reuse_block: bool = False, + ) -> list[tuple[str, int, str, int]]: + """ + Retrieves CRv4 weight commit information for a specific subnet. + + Arguments: + netuid (int): The unique identifier of the subnet. + block (Optional[int]): The blockchain block number for the query. Default is ``None``. + block_hash: The hash of the block to retrieve the stake from. Do not specify if using block + or reuse_block + reuse_block: Whether to use the last-used block. Do not set if using block_hash or block. + + Returns: + A list of commit details, where each item contains: + - ss58_address: The address of the committer. + - commit_block: The block number when the commitment was made. + - commit_message: The commit message. + - reveal_round: The round when the commitment was revealed. + + The list may be empty if there are no commits found. + """ + block_hash = await self.determine_block_hash( + block=block, block_hash=block_hash, reuse_block=reuse_block + ) + result = await self.substrate.query_map( + module="SubtensorModule", + storage_function="TimelockedWeightCommits", + params=[netuid], + block_hash=block_hash, + ) + + commits = result.records[0][1] if result.records else [] + return [WeightCommitInfo.from_vec_u8_v2(commit) for commit in commits] + # TODO: remove unused parameters in SDK.v10 async def get_unstake_fee( self, diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 74cec3fbd7..5158a40b7e 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -1945,6 +1945,35 @@ def get_subnet_prices( prices.update({0: Balance.from_tao(1)}) return prices + def get_timelocked_weight_commits( + self, netuid: int, block: Optional[int] = None + ) -> list[tuple[str, int, str, int]]: + """ + Retrieves CRv4 weight commit information for a specific subnet. + + Arguments: + netuid (int): The unique identifier of the subnet. + block (Optional[int]): The blockchain block number for the query. Default is ``None``. + + Returns: + A list of commit details, where each item contains: + - ss58_address: The address of the committer. + - commit_block: The block number when the commitment was made. + - commit_message: The commit message. + - reveal_round: The round when the commitment was revealed. + + The list may be empty if there are no commits found. + """ + result = self.substrate.query_map( + module="SubtensorModule", + storage_function="TimelockedWeightCommits", + params=[netuid], + block_hash=self.determine_block_hash(block=block), + ) + + commits = result.records[0][1] if result.records else [] + return [WeightCommitInfo.from_vec_u8_v2(commit) for commit in commits] + # TODO: remove unused parameters in SDK.v10 def get_unstake_fee( self, diff --git a/bittensor/core/subtensor_api/commitments.py b/bittensor/core/subtensor_api/commitments.py index 8a9c49bd30..ff130a3e54 100644 --- a/bittensor/core/subtensor_api/commitments.py +++ b/bittensor/core/subtensor_api/commitments.py @@ -22,5 +22,6 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]): self.get_revealed_commitment_by_hotkey = ( subtensor.get_revealed_commitment_by_hotkey ) + self.get_timelocked_weight_commits = subtensor.get_timelocked_weight_commits self.set_commitment = subtensor.set_commitment self.set_reveal_commitment = subtensor.set_reveal_commitment diff --git a/bittensor/core/subtensor_api/utils.py b/bittensor/core/subtensor_api/utils.py index adef4f31b1..67399a37ed 100644 --- a/bittensor/core/subtensor_api/utils.py +++ b/bittensor/core/subtensor_api/utils.py @@ -106,6 +106,9 @@ def add_legacy_methods(subtensor: "SubtensorApi"): subtensor._subtensor.get_subnet_validator_permits ) subtensor.get_subnets = subtensor._subtensor.get_subnets + subtensor.get_timelocked_weight_commits = ( + subtensor._subtensor.get_timelocked_weight_commits + ) subtensor.get_timestamp = subtensor._subtensor.get_timestamp subtensor.get_total_subnets = subtensor._subtensor.get_total_subnets subtensor.get_transfer_fee = subtensor._subtensor.get_transfer_fee diff --git a/tests/e2e_tests/test_commit_reveal.py b/tests/e2e_tests/test_commit_reveal.py index d4088ed0f5..2531326583 100644 --- a/tests/e2e_tests/test_commit_reveal.py +++ b/tests/e2e_tests/test_commit_reveal.py @@ -170,7 +170,7 @@ async def test_commit_and_reveal_weights_cr4(local_chain, subtensor, alice_walle ) # Fetch current commits pending on the chain - commits_on_chain = subtensor.commitments.get_current_weight_commit_info_v2( + commits_on_chain = subtensor.commitments.get_timelocked_weight_commits( netuid=alice_subnet_netuid ) address, commit_block, commit, reveal_round = commits_on_chain[0] @@ -219,9 +219,7 @@ async def test_commit_and_reveal_weights_cr4(local_chain, subtensor, alice_walle # Now that the commit has been revealed, there shouldn't be any pending commits assert ( - subtensor.commitments.get_current_weight_commit_info_v2( - netuid=alice_subnet_netuid - ) + subtensor.commitments.get_timelocked_weight_commits(netuid=alice_subnet_netuid) == [] ) @@ -395,7 +393,7 @@ async def test_async_commit_and_reveal_weights_cr4( # Fetch current commits pending on the chain commits_on_chain = ( - await async_subtensor.commitments.get_current_weight_commit_info_v2( + await async_subtensor.commitments.get_timelocked_weight_commits( netuid=alice_subnet_netuid ) ) @@ -450,7 +448,7 @@ async def test_async_commit_and_reveal_weights_cr4( # Now that the commit has been revealed, there shouldn't be any pending commits assert ( - await async_subtensor.commitments.get_current_weight_commit_info_v2( + await async_subtensor.commitments.get_timelocked_weight_commits( netuid=alice_subnet_netuid ) == [] diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 8c6a5e9eb9..e1bf1420dd 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -4120,3 +4120,34 @@ async def test_get_stake_weight(subtensor, mocker): block_hash=mock_determine_block_hash.return_value, ) assert result == expected_result + + +@pytest.mark.asyncio +async def test_get_timelocked_weight_commits(subtensor, mocker): + """Verify that `get_timelocked_weight_commits` method calls proper methods and returns the correct value.""" + # Preps + netuid = mocker.Mock() + + mock_determine_block_hash = mocker.patch.object( + subtensor, + "determine_block_hash", + ) + mocked_query_map = mocker.AsyncMock( + autospec=async_subtensor.AsyncSubstrateInterface.query_map, + ) + subtensor.substrate.query_map = mocked_query_map + + # Call + result = await subtensor.get_timelocked_weight_commits(netuid=netuid) + + # Asserts + mock_determine_block_hash.assert_awaited_once_with( + block=None, block_hash=None, reuse_block=False + ) + mocked_query_map.assert_awaited_once_with( + module="SubtensorModule", + storage_function="TimelockedWeightCommits", + params=[netuid], + block_hash=mock_determine_block_hash.return_value, + ) + assert result == [] diff --git a/tests/unit_tests/test_subtensor.py b/tests/unit_tests/test_subtensor.py index aa5121408e..78d9ffeaa9 100644 --- a/tests/unit_tests/test_subtensor.py +++ b/tests/unit_tests/test_subtensor.py @@ -4305,3 +4305,31 @@ def test_get_stake_weight(subtensor, mocker): block_hash=mock_determine_block_hash.return_value, ) assert result == expected_result + + +def test_get_timelocked_weight_commits(subtensor, mocker): + """Verify that `get_timelocked_weight_commits` method calls proper methods and returns the correct value.""" + # Preps + netuid = mocker.Mock() + + mock_determine_block_hash = mocker.patch.object( + subtensor, + "determine_block_hash", + ) + mocked_query_map = mocker.patch.object( + subtensor.substrate, + "query_map", + ) + + # Call + result = subtensor.get_timelocked_weight_commits(netuid=netuid) + + # Asserts + mock_determine_block_hash.assert_called_once_with(block=None) + mocked_query_map.assert_called_once_with( + module="SubtensorModule", + storage_function="TimelockedWeightCommits", + params=[netuid], + block_hash=mock_determine_block_hash.return_value, + ) + assert result == []