Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4b15803
add reset_bonds flag
andreea-popescu-reef Apr 3, 2025
a614c21
add get_last_commitment_bonds_reset_block
andreea-popescu-reef Apr 4, 2025
b651960
rebase and fix
andreea-popescu-reef Jun 3, 2025
0ffe5b9
tests
andreea-popescu-reef Jun 3, 2025
34d157a
Update bittensor/core/extrinsics/asyncex/serving.py
andreea-popescu-reef Jun 16, 2025
6ae9f9e
Update bittensor/core/extrinsics/serving.py
andreea-popescu-reef Jun 16, 2025
d3bcadd
fix async reset_bonds
andreea-popescu-reef Jun 16, 2025
8f3e366
Update bittensor/core/extrinsics/serving.py
andreea-popescu-reef Jun 18, 2025
1b36211
Update bittensor/core/subtensor_api/commitments.py
andreea-popescu-reef Jun 18, 2025
0b07baf
Update bittensor/core/subtensor_api/utils.py
andreea-popescu-reef Jun 18, 2025
dbe6ae6
Update bittensor/core/subtensor.py
andreea-popescu-reef Jun 18, 2025
8f6a3f7
Update bittensor/core/subtensor.py
andreea-popescu-reef Jun 18, 2025
80957e4
Update bittensor/core/extrinsics/serving.py
andreea-popescu-reef Jun 18, 2025
7bb2df1
Update bittensor/core/async_subtensor.py
andreea-popescu-reef Jun 18, 2025
0b47393
Update bittensor/core/chain_data/utils.py
andreea-popescu-reef Jun 18, 2025
ca3c9f4
Update bittensor/core/extrinsics/asyncex/serving.py
andreea-popescu-reef Jun 18, 2025
bf9c0e1
better docstring
andreea-popescu-reef Jun 18, 2025
77d73cf
ruff
andreea-popescu-reef Jun 18, 2025
79318aa
Update bittensor/core/async_subtensor.py
zyzniewski-reef Jun 27, 2025
6928e38
Merge branch 'staging' into reset_bonds
zyzniewski-reef Jun 27, 2025
a78a038
ruff
zyzniewski Jun 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from bittensor.core.chain_data.chain_identity import ChainIdentity
from bittensor.core.chain_data.delegate_info import DelegatedInfo
from bittensor.core.chain_data.utils import (
decode_block,
decode_metadata,
decode_revealed_commitment,
decode_revealed_commitment_with_hotkey,
Expand All @@ -55,6 +56,7 @@
root_register_extrinsic,
)
from bittensor.core.extrinsics.asyncex.serving import (
get_last_bonds_reset,
publish_metadata,
get_metadata,
)
Expand Down Expand Up @@ -1152,6 +1154,32 @@ async def get_commitment(
except TypeError:
return ""

async def get_last_commitment_bonds_reset_block(
self, netuid: int, uid: int
) -> Optional[int]:
"""
Retrieves the last block number when the bonds reset were triggered by publish_metadata for a specific neuron.
Arguments:
netuid (int): The unique identifier of the subnetwork.
uid (int): The unique identifier of the neuron.
Returns:
Optional[int]: The block number when the bonds were last reset, or None if not found.
"""

metagraph = await self.metagraph(netuid)
try:
hotkey = metagraph.hotkeys[uid] # type: ignore
except IndexError:
logging.error(
"Your uid is not in the hotkeys. Please double-check your UID."
)
return None
block = await get_last_bonds_reset(self, netuid, hotkey)
try:
return decode_block(block)
except TypeError:
return ""

async def get_all_commitments(
self,
netuid: int,
Expand Down
12 changes: 12 additions & 0 deletions bittensor/core/chain_data/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Optional, Union, TYPE_CHECKING

from scalecodec.base import RuntimeConfiguration, ScaleBytes
from async_substrate_interface.types import ScaleObj
from scalecodec.type_registry import load_type_registry_preset
from scalecodec.utils.ss58 import ss58_encode

Expand Down Expand Up @@ -140,6 +141,17 @@ def decode_metadata(metadata: dict) -> str:
return bytes(bytes_tuple).decode()


def decode_block(data: bytes) -> int:
"""
Decode the block data from the given input if it is not None.
Arguments:
data (bytes): The block data to decode.
Returns:
int: The decoded block.
"""
return int(data.value) if isinstance(data, ScaleObj) else data


def decode_revealed_commitment(encoded_data) -> tuple[int, str]:
"""
Decode the revealed commitment data from the given input if it is not None.
Expand Down
27 changes: 26 additions & 1 deletion bittensor/core/extrinsics/asyncex/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ async def publish_metadata(
wait_for_inclusion: bool = False,
wait_for_finalization: bool = True,
period: Optional[int] = None,
reset_bonds: bool = False,
) -> bool:
"""
Publishes metadata on the Bittensor network using the specified wallet and network identifier.
Expand All @@ -256,6 +257,7 @@ async def publish_metadata(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
reset_bonds (bool): If ``True``, the function will reset the bonds for the neuron. Defaults to ``False``.

Returns:
bool: ``True`` if the metadata was successfully published (and finalized if specified). ``False`` otherwise.
Expand All @@ -269,13 +271,17 @@ async def publish_metadata(
logging.error(unlock.message)
return False

fields = [{f"{data_type}": data}]
if reset_bonds:
fields.append({"ResetBondsFlag": b""})

async with subtensor.substrate as substrate:
call = await substrate.compose_call(
call_module="Commitments",
call_function="set_commitment",
call_params={
"netuid": netuid,
"info": {"fields": [[{f"{data_type}": data}]]},
"info": {"fields": [fields]},
},
)

Expand Down Expand Up @@ -314,3 +320,22 @@ async def get_metadata(
reuse_block_hash=reuse_block,
)
return commit_data


async def get_last_bonds_reset(
subtensor: "AsyncSubtensor",
netuid: int,
hotkey: str,
block: Optional[int] = None,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> bytes:
"""Fetches the last bonds reset triggered at commitment from the blockchain for a given hotkey and netuid."""
block_hash = await subtensor.determine_block_hash(block, block_hash, reuse_block)
block = await subtensor.substrate.query(
module="Commitments",
storage_function="LastBondsReset",
params=[netuid, hotkey],
block_hash=block_hash,
)
return block
21 changes: 20 additions & 1 deletion bittensor/core/extrinsics/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ def publish_metadata(
wait_for_inclusion: bool = False,
wait_for_finalization: bool = True,
period: Optional[int] = None,
reset_bonds: bool = False,
) -> bool:
"""
Publishes metadata on the Bittensor network using the specified wallet and network identifier.
Expand All @@ -253,6 +254,7 @@ def publish_metadata(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
reset_bonds (bool): If ``True``, the function will reset the bonds for the neuron. Defaults to ``False``.

Returns:
bool: ``True`` if the metadata was successfully published (and finalized if specified). ``False`` otherwise.
Expand All @@ -266,12 +268,16 @@ def publish_metadata(
logging.error(unlock.message)
return False

fields = [{f"{data_type}": data}]
if reset_bonds:
fields.append({"ResetBondsFlag": b""})

call = subtensor.substrate.compose_call(
call_module="Commitments",
call_function="set_commitment",
call_params={
"netuid": netuid,
"info": {"fields": [[{f"{data_type}": data}]]},
"info": {"fields": [fields]},
},
)

Expand Down Expand Up @@ -300,3 +306,16 @@ def get_metadata(
block_hash=subtensor.determine_block_hash(block),
)
return commit_data


def get_last_bonds_reset(
subtensor: "Subtensor", netuid: int, hotkey: str, block: Optional[int] = None
) -> bytes:
"""Fetches the last bonds reset triggered at commitment from the blockchain for a given hotkey and netuid."""
block = subtensor.substrate.query(
module="Commitments",
storage_function="LastBondsReset",
params=[netuid, hotkey],
block_hash=subtensor.determine_block_hash(block),
)
return block
27 changes: 27 additions & 0 deletions bittensor/core/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
)
from bittensor.core.chain_data.chain_identity import ChainIdentity
from bittensor.core.chain_data.utils import (
decode_block,
decode_metadata,
decode_revealed_commitment,
decode_revealed_commitment_with_hotkey,
Expand Down Expand Up @@ -57,6 +58,7 @@
set_root_weights_extrinsic,
)
from bittensor.core.extrinsics.serving import (
get_last_bonds_reset,
publish_metadata,
get_metadata,
serve_axon_extrinsic,
Expand Down Expand Up @@ -891,6 +893,31 @@ def get_commitment(self, netuid: int, uid: int, block: Optional[int] = None) ->
except TypeError:
return ""

def get_last_commitment_bonds_reset_block(
self, netuid: int, uid: int
) -> Optional[int]:
"""
Retrieves the last block number when the bonds reset were triggered by publish_metadata for a specific neuron.
Arguments:
netuid (int): The unique identifier of the subnetwork.
uid (int): The unique identifier of the neuron.
Returns:
Optional[int]: The block number when the bonds were last reset, or None if not found.
"""

metagraph = self.metagraph(netuid)
try:
hotkey = metagraph.hotkeys[uid] # type: ignore
except IndexError:
logging.error(
"Your uid is not in the hotkeys. Please double-check your UID."
)
return None
block = get_last_bonds_reset(self, netuid, hotkey)
if block is None:
return None
return decode_block(block)

def get_all_commitments(
self, netuid: int, block: Optional[int] = None
) -> dict[str, str]:
Expand Down
3 changes: 3 additions & 0 deletions bittensor/core/subtensor_api/commitments.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]):
self.get_all_commitments = subtensor.get_all_commitments
self.get_all_revealed_commitments = subtensor.get_all_revealed_commitments
self.get_commitment = subtensor.get_commitment
self.get_last_commitment_bonds_reset_block = (
subtensor.get_last_commitment_bonds_reset_block
)
self.get_current_weight_commit_info = subtensor.get_current_weight_commit_info
self.get_revealed_commitment = subtensor.get_revealed_commitment
self.get_revealed_commitment_by_hotkey = (
Expand Down
3 changes: 3 additions & 0 deletions bittensor/core/subtensor_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def add_legacy_methods(subtensor: "SubtensorApi"):
subtensor.get_children = subtensor._subtensor.get_children
subtensor.get_children_pending = subtensor._subtensor.get_children_pending
subtensor.get_commitment = subtensor._subtensor.get_commitment
subtensor.get_last_commitment_bonds_reset_block = (
subtensor._subtensor.get_last_commitment_bonds_reset_block
)
subtensor.get_current_block = subtensor._subtensor.get_current_block
subtensor.get_current_weight_commit_info = (
subtensor._subtensor.get_current_weight_commit_info
Expand Down
27 changes: 27 additions & 0 deletions tests/unit_tests/test_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,33 @@ def test_get_commitment(subtensor, mocker):
assert result == expected_result


def test_get_last_commitment_bonds_reset_block(subtensor, mocker):
"""Successful get_last_commitment_bonds_reset_block call."""
# Preps
fake_netuid = 1
fake_uid = 2
fake_hotkey = "hotkey"
expected_result = 3

mocked_get_last_bonds_reset = mocker.patch.object(
subtensor_module, "get_last_bonds_reset"
)
mocked_get_last_bonds_reset.return_value = expected_result

mocked_metagraph = mocker.MagicMock()
subtensor.metagraph = mocked_metagraph
mocked_metagraph.return_value.hotkeys = {fake_uid: fake_hotkey}

# Call
result = subtensor.get_last_commitment_bonds_reset_block(
netuid=fake_netuid, uid=fake_uid
)

# Assertions
mocked_get_last_bonds_reset.assert_called_once()
assert result == expected_result


def test_min_allowed_weights(subtensor, mocker):
"""Successful min_allowed_weights call."""
fake_netuid = 1
Expand Down
Loading