Skip to content

Commit d7e4d68

Browse files
authored
Merge branch 'staging' into feat/roman/selective_metagraph_back
2 parents 3e8b103 + 5c828cc commit d7e4d68

22 files changed

+1103
-84
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ workflows:
267267
- build-and-test:
268268
matrix:
269269
parameters:
270-
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7"]
270+
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7", "3.13.1" ]
271271
requires:
272272
- check-if-pr-is-draft
273273
- unit-tests-all-python-versions:
@@ -276,7 +276,7 @@ workflows:
276276
- lint-and-type-check:
277277
matrix:
278278
parameters:
279-
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7"]
279+
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7", "3.13.1" ]
280280
requires:
281281
- check-if-pr-is-draft
282282
#- coveralls:

bittensor/core/async_subtensor.py

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from bittensor.core.chain_data.chain_identity import ChainIdentity
3434
from bittensor.core.chain_data.delegate_info import DelegatedInfo
3535
from bittensor.core.chain_data.utils import (
36+
decode_block,
3637
decode_metadata,
3738
decode_revealed_commitment,
3839
decode_revealed_commitment_with_hotkey,
@@ -60,6 +61,7 @@
6061
root_register_extrinsic,
6162
)
6263
from bittensor.core.extrinsics.asyncex.serving import (
64+
get_last_bonds_reset,
6365
publish_metadata,
6466
get_metadata,
6567
)
@@ -75,6 +77,7 @@
7577
)
7678
from bittensor.core.extrinsics.asyncex.transfer import transfer_extrinsic
7779
from bittensor.core.extrinsics.asyncex.unstaking import (
80+
unstake_all_extrinsic,
7881
unstake_extrinsic,
7982
unstake_multiple_extrinsic,
8083
)
@@ -1172,6 +1175,34 @@ async def get_commitment(
11721175
except TypeError:
11731176
return ""
11741177

1178+
async def get_last_commitment_bonds_reset_block(
1179+
self, netuid: int, uid: int
1180+
) -> Optional[int]:
1181+
"""
1182+
Retrieves the last block number when the bonds reset were triggered by publish_metadata for a specific neuron.
1183+
1184+
Arguments:
1185+
netuid (int): The unique identifier of the subnetwork.
1186+
uid (int): The unique identifier of the neuron.
1187+
1188+
Returns:
1189+
Optional[int]: The block number when the bonds were last reset, or None if not found.
1190+
"""
1191+
1192+
metagraph = await self.metagraph(netuid)
1193+
try:
1194+
hotkey = metagraph.hotkeys[uid]
1195+
except IndexError:
1196+
logging.error(
1197+
"Your uid is not in the hotkeys. Please double-check your UID."
1198+
)
1199+
return None
1200+
block = await get_last_bonds_reset(self, netuid, hotkey)
1201+
try:
1202+
return decode_block(block)
1203+
except TypeError:
1204+
return ""
1205+
11751206
async def get_all_commitments(
11761207
self,
11771208
netuid: int,
@@ -1202,7 +1233,7 @@ async def get_all_commitments(
12021233
)
12031234
result = {}
12041235
async for id_, value in query:
1205-
result[decode_account_id(id_[0])] = decode_metadata(value)
1236+
result[decode_account_id(id_[0])] = decode_metadata(value.value)
12061237
return result
12071238

12081239
async def get_revealed_commitment_by_hotkey(
@@ -2309,7 +2340,7 @@ async def get_subnet_hyperparameters(
23092340
"""
23102341
result = await self.query_runtime_api(
23112342
runtime_api="SubnetInfoRuntimeApi",
2312-
method="get_subnet_hyperparams",
2343+
method="get_subnet_hyperparams_v2",
23132344
params=[netuid],
23142345
block=block,
23152346
block_hash=block_hash,
@@ -3125,6 +3156,7 @@ async def subnet(
31253156

31263157
if isinstance(decoded := query.decode(), dict):
31273158
return DynamicInfo.from_dict(decoded)
3159+
return None
31283160

31293161
async def subnet_exists(
31303162
self,
@@ -4639,6 +4671,90 @@ async def unstake(
46394671
unstake_all=unstake_all,
46404672
)
46414673

4674+
async def unstake_all(
4675+
self,
4676+
wallet: "Wallet",
4677+
hotkey: str,
4678+
netuid: int,
4679+
rate_tolerance: Optional[float] = 0.005,
4680+
wait_for_inclusion: bool = True,
4681+
wait_for_finalization: bool = False,
4682+
period: Optional[int] = None,
4683+
) -> tuple[bool, str]:
4684+
"""Unstakes all TAO/Alpha associated with a hotkey from the specified subnets on the Bittensor network.
4685+
4686+
Arguments:
4687+
wallet: The wallet of the stake owner.
4688+
hotkey: The SS58 address of the hotkey to unstake from.
4689+
netuid: The unique identifier of the subnet.
4690+
rate_tolerance: The maximum allowed price change ratio when unstaking. For example, 0.005 = 0.5% maximum
4691+
price decrease. If not passed (None), then unstaking goes without price limit. Default is 0.005.
4692+
wait_for_inclusion: Waits for the transaction to be included in a block. Default is `True`.
4693+
wait_for_finalization: Waits for the transaction to be finalized on the blockchain. Default is `False`.
4694+
period: The number of blocks during which the transaction will remain valid after it's submitted. If the
4695+
transaction is not included in a block within that number of blocks, it will expire and be rejected. You
4696+
can think of it as an expiration date for the transaction. Default is `None`.
4697+
4698+
Returns:
4699+
tuple[bool, str]:
4700+
A tuple containing:
4701+
- `True` and a success message if the unstake operation succeeded;
4702+
- `False` and an error message otherwise.
4703+
4704+
Example:
4705+
# If you would like to unstake all stakes in all subnets safely, use default `rate_tolerance` or pass your
4706+
value:
4707+
import bittensor as bt
4708+
4709+
subtensor = bt.AsyncSubtensor()
4710+
wallet = bt.Wallet("my_wallet")
4711+
netuid = 14
4712+
hotkey = "5%SOME_HOTKEY_WHERE_IS_YOUR_STAKE_NOW%"
4713+
4714+
wallet_stakes = await subtensor.get_stake_info_for_coldkey(coldkey_ss58=wallet.coldkey.ss58_address)
4715+
4716+
for stake in wallet_stakes:
4717+
result = await subtensor.unstake_all(
4718+
wallet=wallet,
4719+
hotkey_ss58=stake.hotkey_ss58,
4720+
netuid=stake.netuid,
4721+
)
4722+
print(result)
4723+
4724+
# If you would like to unstake all stakes in all subnets unsafely, use `rate_tolerance=None`:
4725+
import bittensor as bt
4726+
4727+
subtensor = bt.AsyncSubtensor()
4728+
wallet = bt.Wallet("my_wallet")
4729+
netuid = 14
4730+
hotkey = "5%SOME_HOTKEY_WHERE_IS_YOUR_STAKE_NOW%"
4731+
4732+
wallet_stakes = await subtensor.get_stake_info_for_coldkey(coldkey_ss58=wallet.coldkey.ss58_address)
4733+
4734+
for stake in wallet_stakes:
4735+
result = await subtensor.unstake_all(
4736+
wallet=wallet,
4737+
hotkey_ss58=stake.hotkey_ss58,
4738+
netuid=stake.netuid,
4739+
rate_tolerance=None,
4740+
)
4741+
print(result)
4742+
"""
4743+
if netuid != 0:
4744+
logging.debug(
4745+
f"Unstaking without Alpha price control from subnet [blue]#{netuid}[/blue]."
4746+
)
4747+
return await unstake_all_extrinsic(
4748+
subtensor=self,
4749+
wallet=wallet,
4750+
hotkey=hotkey,
4751+
netuid=netuid,
4752+
rate_tolerance=rate_tolerance,
4753+
wait_for_inclusion=wait_for_inclusion,
4754+
wait_for_finalization=wait_for_finalization,
4755+
period=period,
4756+
)
4757+
46424758
async def unstake_multiple(
46434759
self,
46444760
wallet: "Wallet",

bittensor/core/chain_data/subnet_hyperparameters.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from dataclasses import dataclass
2-
2+
from bittensor.utils.balance import fixed_to_float
33
from bittensor.core.chain_data.info_base import InfoBase
44

55

@@ -36,6 +36,12 @@ class SubnetHyperparameters(InfoBase):
3636
alpha_high (int): High value of alpha.
3737
alpha_low (int): Low value of alpha.
3838
liquid_alpha_enabled (bool): Flag indicating if liquid alpha is enabled.
39+
alpha_sigmoid_steepness (float):
40+
yuma_version (int): Version of yuma.
41+
subnet_is_active (bool): Indicates if subnet is active after START CALL.
42+
transfers_enabled (bool): Flag indicating if transfers are enabled.
43+
bonds_reset_enabled (bool): Flag indicating if bonds are reset enabled.
44+
user_liquidity_enabled (bool): Flag indicating if user liquidity is enabled.
3945
"""
4046

4147
rho: int
@@ -65,6 +71,12 @@ class SubnetHyperparameters(InfoBase):
6571
alpha_high: int
6672
alpha_low: int
6773
liquid_alpha_enabled: bool
74+
alpha_sigmoid_steepness: float
75+
yuma_version: int
76+
subnet_is_active: bool
77+
transfers_enabled: bool
78+
bonds_reset_enabled: bool
79+
user_liquidity_enabled: bool
6880

6981
@classmethod
7082
def _from_dict(cls, decoded: dict) -> "SubnetHyperparameters":
@@ -75,7 +87,11 @@ def _from_dict(cls, decoded: dict) -> "SubnetHyperparameters":
7587
adjustment_interval=decoded["adjustment_interval"],
7688
alpha_high=decoded["alpha_high"],
7789
alpha_low=decoded["alpha_low"],
90+
alpha_sigmoid_steepness=fixed_to_float(
91+
decoded["alpha_sigmoid_steepness"], frac_bits=32
92+
),
7893
bonds_moving_avg=decoded["bonds_moving_avg"],
94+
bonds_reset_enabled=decoded["bonds_reset_enabled"],
7995
commit_reveal_weights_enabled=decoded["commit_reveal_weights_enabled"],
8096
commit_reveal_period=decoded["commit_reveal_period"],
8197
difficulty=decoded["difficulty"],
@@ -93,8 +109,12 @@ def _from_dict(cls, decoded: dict) -> "SubnetHyperparameters":
93109
registration_allowed=decoded["registration_allowed"],
94110
rho=decoded["rho"],
95111
serving_rate_limit=decoded["serving_rate_limit"],
112+
subnet_is_active=decoded["subnet_is_active"],
96113
target_regs_per_interval=decoded["target_regs_per_interval"],
97114
tempo=decoded["tempo"],
115+
transfers_enabled=decoded["transfers_enabled"],
116+
user_liquidity_enabled=decoded["user_liquidity_enabled"],
98117
weights_rate_limit=decoded["weights_rate_limit"],
99118
weights_version=decoded["weights_version"],
119+
yuma_version=decoded["yuma_version"],
100120
)

bittensor/core/chain_data/utils.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Optional, Union, TYPE_CHECKING
55

66
from scalecodec.base import RuntimeConfiguration, ScaleBytes
7+
from async_substrate_interface.types import ScaleObj
78
from scalecodec.type_registry import load_type_registry_preset
89
from scalecodec.utils.ss58 import ss58_encode
910

@@ -136,10 +137,24 @@ def process_stake_data(stake_data: list) -> dict:
136137

137138
def decode_metadata(metadata: dict) -> str:
138139
commitment = metadata["info"]["fields"][0][0]
139-
bytes_tuple = commitment[next(iter(commitment.keys()))][0]
140+
bytes_tuple_ = commitment[next(iter(commitment.keys()))]
141+
bytes_tuple = bytes_tuple_[0] if len(bytes_tuple_) > 0 else bytes_tuple_
140142
return bytes(bytes_tuple).decode()
141143

142144

145+
def decode_block(data: bytes) -> int:
146+
"""
147+
Decode the block data from the given input if it is not None.
148+
149+
Arguments:
150+
data (bytes): The block data to decode.
151+
152+
Returns:
153+
int: The decoded block.
154+
"""
155+
return int(data.value) if isinstance(data, ScaleObj) else data
156+
157+
143158
def decode_revealed_commitment(encoded_data) -> tuple[int, str]:
144159
"""
145160
Decode the revealed commitment data from the given input if it is not None.

bittensor/core/extrinsics/asyncex/serving.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ async def publish_metadata(
236236
wait_for_inclusion: bool = False,
237237
wait_for_finalization: bool = True,
238238
period: Optional[int] = None,
239+
reset_bonds: bool = False,
239240
) -> bool:
240241
"""
241242
Publishes metadata on the Bittensor network using the specified wallet and network identifier.
@@ -256,6 +257,7 @@ async def publish_metadata(
256257
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted. If
257258
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
258259
You can think of it as an expiration date for the transaction.
260+
reset_bonds (bool): If `True`, the function will reset the bonds for the neuron. Defaults to `False`.
259261
260262
Returns:
261263
bool: ``True`` if the metadata was successfully published (and finalized if specified). ``False`` otherwise.
@@ -269,13 +271,17 @@ async def publish_metadata(
269271
logging.error(unlock.message)
270272
return False
271273

274+
fields = [{f"{data_type}": data}]
275+
if reset_bonds:
276+
fields.append({"ResetBondsFlag": b""})
277+
272278
async with subtensor.substrate as substrate:
273279
call = await substrate.compose_call(
274280
call_module="Commitments",
275281
call_function="set_commitment",
276282
call_params={
277283
"netuid": netuid,
278-
"info": {"fields": [[{f"{data_type}": data}]]},
284+
"info": {"fields": [fields]},
279285
},
280286
)
281287

@@ -314,3 +320,22 @@ async def get_metadata(
314320
reuse_block_hash=reuse_block,
315321
)
316322
return commit_data
323+
324+
325+
async def get_last_bonds_reset(
326+
subtensor: "AsyncSubtensor",
327+
netuid: int,
328+
hotkey: str,
329+
block: Optional[int] = None,
330+
block_hash: Optional[str] = None,
331+
reuse_block: bool = False,
332+
) -> bytes:
333+
"""Fetches the last bonds reset triggered at commitment from the blockchain for a given hotkey and netuid."""
334+
block_hash = await subtensor.determine_block_hash(block, block_hash, reuse_block)
335+
block = await subtensor.substrate.query(
336+
module="Commitments",
337+
storage_function="LastBondsReset",
338+
params=[netuid, hotkey],
339+
block_hash=block_hash,
340+
)
341+
return block

0 commit comments

Comments
 (0)