Skip to content

Commit 6caa770

Browse files
author
Roman
committed
Merge branch 'staging' into feat/roman/test-run-tests-without-building
2 parents 336af8e + 9730f51 commit 6caa770

30 files changed

+1088
-311
lines changed

.github/workflows/e2e-subtensor-tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ concurrency:
66

77
on:
88
push:
9-
branches: [main, development, staging]
9+
branches: [master, development, staging]
1010

1111
pull_request:
12-
branches: [main, development, staging]
12+
branches: [master, development, staging]
1313
types: [ opened, synchronize, reopened, ready_for_review ]
1414

1515
workflow_dispatch:

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## 9.0.5 /2025-03-12
3+
## 9.1.0 /2025-03-12
44

55
## What's Changed
66
* Refactor duplicated unittests code by @zyzniewski-reef in https://github.com/opentensor/bittensor/pull/2724
@@ -12,8 +12,13 @@
1212
* All metagraph subtensor methods now use block by @thewhaleking in https://github.com/opentensor/bittensor/pull/2738
1313
* Tests: increse test_incentive timeout + fix sudo_set_weights_set_rate_limit by @zyzniewski-reef in https://github.com/opentensor/bittensor/pull/2739
1414
* Feat/safe staking by @ibraheem-opentensor in https://github.com/opentensor/bittensor/pull/2736
15+
* 9.0.5: Bumps version and changelog by @ibraheem-opentensor in https://github.com/opentensor/bittensor/pull/2741
16+
* Tests: enable E2E test_batch_operations by @zyzniewski-reef in https://github.com/opentensor/bittensor/pull/2744
17+
* Fix: burned_register supports root subnet (netuid=0 param) by @zyzniewski-reef in https://github.com/opentensor/bittensor/pull/2732
18+
* Feat: set_delegate_take by @zyzniewski-reef in https://github.com/opentensor/bittensor/pull/2731
19+
* Renames rate_threshold -> rate_tolerance by @ibraheem-opentensor in https://github.com/opentensor/bittensor/pull/2745
1520

16-
**Full Changelog**: https://github.com/opentensor/bittensor/compare/v9.0.4...v9.0.5
21+
**Full Changelog**: https://github.com/opentensor/bittensor/compare/v9.0.4...v9.1.0
1722

1823
## 9.0.4 /2025-03-06
1924

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
9.0.5
1+
9.1.0

bittensor/core/async_subtensor.py

Lines changed: 115 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from bittensor.core.chain_data.delegate_info import DelegatedInfo
3232
from bittensor.core.chain_data.utils import decode_metadata
3333
from bittensor.core.config import Config
34-
from bittensor.core.errors import SubstrateRequestException
34+
from bittensor.core.errors import ChainError, SubstrateRequestException
3535
from bittensor.core.extrinsics.asyncex.commit_reveal import commit_reveal_v3_extrinsic
3636
from bittensor.core.extrinsics.asyncex.registration import (
3737
burned_register_extrinsic,
@@ -57,6 +57,10 @@
5757
add_stake_extrinsic,
5858
add_stake_multiple_extrinsic,
5959
)
60+
from bittensor.core.extrinsics.asyncex.take import (
61+
decrease_take_extrinsic,
62+
increase_take_extrinsic,
63+
)
6064
from bittensor.core.extrinsics.asyncex.transfer import transfer_extrinsic
6165
from bittensor.core.extrinsics.asyncex.unstaking import (
6266
unstake_extrinsic,
@@ -1111,7 +1115,7 @@ async def get_delegate_take(
11111115
block: Optional[int] = None,
11121116
block_hash: Optional[str] = None,
11131117
reuse_block: bool = False,
1114-
) -> Optional[float]:
1118+
) -> float:
11151119
"""
11161120
Retrieves the delegate 'take' percentage for a neuron identified by its hotkey. The 'take' represents the
11171121
percentage of rewards that the delegate claims from its nominators' stakes.
@@ -1123,7 +1127,7 @@ async def get_delegate_take(
11231127
reuse_block (bool): Whether to reuse the last-used block hash.
11241128
11251129
Returns:
1126-
Optional[float]: The delegate take percentage, None if not available.
1130+
float: The delegate take percentage.
11271131
11281132
The delegate take is a critical parameter in the network's incentive structure, influencing the distribution of
11291133
rewards among neurons and their nominators.
@@ -1135,11 +1139,8 @@ async def get_delegate_take(
11351139
reuse_block=reuse_block,
11361140
params=[hotkey_ss58],
11371141
)
1138-
return (
1139-
None
1140-
if result is None
1141-
else u16_normalized_float(getattr(result, "value", 0))
1142-
)
1142+
1143+
return u16_normalized_float(result.value) # type: ignore
11431144

11441145
async def get_delegated(
11451146
self,
@@ -2748,6 +2749,7 @@ async def sign_and_send_extrinsic(
27482749
use_nonce: bool = False,
27492750
period: Optional[int] = None,
27502751
nonce_key: str = "hotkey",
2752+
raise_error: bool = False,
27512753
) -> tuple[bool, str]:
27522754
"""
27532755
Helper method to sign and submit an extrinsic call to chain.
@@ -2758,6 +2760,7 @@ async def sign_and_send_extrinsic(
27582760
wait_for_inclusion (bool): whether to wait until the extrinsic call is included on the chain
27592761
wait_for_finalization (bool): whether to wait until the extrinsic call is finalized on the chain
27602762
sign_with: the wallet's keypair to use for the signing. Options are "coldkey", "hotkey", "coldkeypub"
2763+
raise_error: raises relevant exception rather than returning `False` if unsuccessful.
27612764
27622765
Returns:
27632766
(success, error message)
@@ -2795,9 +2798,15 @@ async def sign_and_send_extrinsic(
27952798
if await response.is_success:
27962799
return True, ""
27972800

2801+
if raise_error:
2802+
raise ChainError.from_error(response.error_message)
2803+
27982804
return False, format_error_message(await response.error_message)
27992805

28002806
except SubstrateRequestException as e:
2807+
if raise_error:
2808+
raise
2809+
28012810
return False, format_error_message(e)
28022811

28032812
# Extrinsics =======================================================================================================
@@ -2812,7 +2821,7 @@ async def add_stake(
28122821
wait_for_finalization: bool = False,
28132822
safe_staking: bool = False,
28142823
allow_partial_stake: bool = False,
2815-
rate_threshold: float = 0.005,
2824+
rate_tolerance: float = 0.005,
28162825
) -> bool:
28172826
"""
28182827
Adds the specified amount of stake to a neuron identified by the hotkey ``SS58`` address.
@@ -2827,11 +2836,11 @@ async def add_stake(
28272836
wait_for_inclusion (bool): Waits for the transaction to be included in a block.
28282837
wait_for_finalization (bool): Waits for the transaction to be finalized on the blockchain.
28292838
safe_staking (bool): If true, enables price safety checks to protect against fluctuating prices. The stake
2830-
will only execute if the price change doesn't exceed the rate threshold. Default is False.
2839+
will only execute if the price change doesn't exceed the rate tolerance. Default is False.
28312840
allow_partial_stake (bool): If true and safe_staking is enabled, allows partial staking when
28322841
the full amount would exceed the price threshold. If false, the entire stake fails if it would
28332842
exceed the threshold. Default is False.
2834-
rate_threshold (float): The maximum allowed price change ratio when staking. For example,
2843+
rate_tolerance (float): The maximum allowed price change ratio when staking. For example,
28352844
0.005 = 0.5% maximum price increase. Only used when safe_staking is True. Default is 0.005.
28362845
28372846
Returns:
@@ -2852,7 +2861,7 @@ async def add_stake(
28522861
wait_for_finalization=wait_for_finalization,
28532862
safe_staking=safe_staking,
28542863
allow_partial_stake=allow_partial_stake,
2855-
rate_threshold=rate_threshold,
2864+
rate_tolerance=rate_tolerance,
28562865
)
28572866

28582867
async def add_stake_multiple(
@@ -2915,6 +2924,14 @@ async def burned_register(
29152924
bool: ``True`` if the registration is successful, False otherwise.
29162925
"""
29172926
async with self:
2927+
if netuid == 0:
2928+
return await root_register_extrinsic(
2929+
subtensor=self,
2930+
wallet=wallet,
2931+
wait_for_inclusion=wait_for_inclusion,
2932+
wait_for_finalization=wait_for_finalization,
2933+
)
2934+
29182935
return await burned_register_extrinsic(
29192936
subtensor=self,
29202937
wallet=wallet,
@@ -3205,35 +3222,6 @@ async def root_register(
32053222
Returns:
32063223
`True` if registration was successful, otherwise `False`.
32073224
"""
3208-
netuid = 0
3209-
logging.info(
3210-
f"Registering on netuid [blue]0[/blue] on network: [blue]{self.network}[/blue]"
3211-
)
3212-
3213-
# Check current recycle amount
3214-
logging.info("Fetching recycle amount & balance.")
3215-
block_hash = block_hash if block_hash else await self.get_block_hash()
3216-
3217-
try:
3218-
recycle_call, balance = await asyncio.gather(
3219-
self.get_hyperparameter(
3220-
param_name="Burn", netuid=netuid, block_hash=block_hash
3221-
),
3222-
self.get_balance(wallet.coldkeypub.ss58_address, block_hash=block_hash),
3223-
)
3224-
except TypeError as e:
3225-
logging.error(f"Unable to retrieve current recycle. {e}")
3226-
return False
3227-
3228-
current_recycle = Balance.from_rao(int(recycle_call))
3229-
3230-
# Check balance is sufficient
3231-
if balance < current_recycle:
3232-
logging.error(
3233-
f"[red]Insufficient balance {balance} to register neuron. "
3234-
f"Current recycle is {current_recycle} TAO[/red]."
3235-
)
3236-
return False
32373225

32383226
return await root_register_extrinsic(
32393227
subtensor=self,
@@ -3281,6 +3269,82 @@ async def root_set_weights(
32813269
wait_for_inclusion=wait_for_inclusion,
32823270
)
32833271

3272+
async def set_delegate_take(
3273+
self,
3274+
wallet: "Wallet",
3275+
hotkey_ss58: str,
3276+
take: float,
3277+
wait_for_inclusion: bool = True,
3278+
wait_for_finalization: bool = True,
3279+
raise_error: bool = False,
3280+
) -> tuple[bool, str]:
3281+
"""
3282+
Sets the delegate 'take' percentage for a neuron identified by its hotkey.
3283+
The 'take' represents the percentage of rewards that the delegate claims from its nominators' stakes.
3284+
3285+
Arguments:
3286+
wallet (bittensor_wallet.Wallet): bittensor wallet instance.
3287+
hotkey_ss58 (str): The ``SS58`` address of the neuron's hotkey.
3288+
take (float): Percentage reward for the delegate.
3289+
wait_for_inclusion (bool): Waits for the transaction to be included in a block.
3290+
wait_for_finalization (bool): Waits for the transaction to be finalized on the blockchain.
3291+
raise_error: Raises relevant exception rather than returning `False` if unsuccessful.
3292+
3293+
Returns:
3294+
tuple[bool, str]: A tuple where the first element is a boolean indicating success or failure of the
3295+
operation, and the second element is a message providing additional information.
3296+
3297+
Raises:
3298+
DelegateTakeTooHigh: Delegate take is too high.
3299+
DelegateTakeTooLow: Delegate take is too low.
3300+
DelegateTxRateLimitExceeded: A transactor exceeded the rate limit for delegate transaction.
3301+
HotKeyAccountNotExists: The hotkey does not exists.
3302+
NonAssociatedColdKey: Request to stake, unstake or subscribe is made by a coldkey that is not associated with the hotkey account.
3303+
bittensor_wallet.errors.PasswordError: Decryption failed or wrong password for decryption provided.
3304+
bittensor_wallet.errors.KeyFileError: Failed to decode keyfile data.
3305+
3306+
The delegate take is a critical parameter in the network's incentive structure, influencing the distribution of
3307+
rewards among neurons and their nominators.
3308+
"""
3309+
3310+
# u16 representation of the take
3311+
take_u16 = int(take * 0xFFFF)
3312+
3313+
current_take = await self.get_delegate_take(hotkey_ss58)
3314+
current_take_u16 = int(current_take * 0xFFFF)
3315+
3316+
if current_take_u16 == take_u16:
3317+
logging.info(":white_heavy_check_mark: [green]Already Set[/green]")
3318+
return True, ""
3319+
3320+
logging.info(f"Updating {hotkey_ss58} take: current={current_take} new={take}")
3321+
3322+
if current_take_u16 < take_u16:
3323+
success, error = await increase_take_extrinsic(
3324+
self,
3325+
wallet,
3326+
hotkey_ss58,
3327+
take_u16,
3328+
wait_for_finalization=wait_for_finalization,
3329+
wait_for_inclusion=wait_for_inclusion,
3330+
raise_error=raise_error,
3331+
)
3332+
else:
3333+
success, error = await decrease_take_extrinsic(
3334+
self,
3335+
wallet,
3336+
hotkey_ss58,
3337+
take_u16,
3338+
wait_for_finalization=wait_for_finalization,
3339+
wait_for_inclusion=wait_for_inclusion,
3340+
raise_error=raise_error,
3341+
)
3342+
3343+
if success:
3344+
logging.info(":white_heavy_check_mark: [green]Take Updated[/green]")
3345+
3346+
return success, error
3347+
32843348
async def set_subnet_identity(
32853349
self,
32863350
wallet: "Wallet",
@@ -3476,7 +3540,7 @@ async def swap_stake(
34763540
wait_for_finalization: bool = False,
34773541
safe_staking: bool = False,
34783542
allow_partial_stake: bool = False,
3479-
rate_threshold: float = 0.005,
3543+
rate_tolerance: float = 0.005,
34803544
) -> bool:
34813545
"""
34823546
Moves stake between subnets while keeping the same coldkey-hotkey pair ownership.
@@ -3491,12 +3555,12 @@ async def swap_stake(
34913555
wait_for_inclusion (bool): Waits for the transaction to be included in a block.
34923556
wait_for_finalization (bool): Waits for the transaction to be finalized on the blockchain.
34933557
safe_staking (bool): If true, enables price safety checks to protect against fluctuating prices. The swap
3494-
will only execute if the price ratio between subnets doesn't exceed the rate threshold.
3558+
will only execute if the price ratio between subnets doesn't exceed the rate tolerance.
34953559
Default is False.
34963560
allow_partial_stake (bool): If true and safe_staking is enabled, allows partial stake swaps when
34973561
the full amount would exceed the price threshold. If false, the entire swap fails if it would
34983562
exceed the threshold. Default is False.
3499-
rate_threshold (float): The maximum allowed increase in the price ratio between subnets
3563+
rate_tolerance (float): The maximum allowed increase in the price ratio between subnets
35003564
(origin_price/destination_price). For example, 0.005 = 0.5% maximum increase. Only used
35013565
when safe_staking is True. Default is 0.005.
35023566
@@ -3506,9 +3570,9 @@ async def swap_stake(
35063570
The price ratio for swap_stake in safe mode is calculated as: origin_subnet_price / destination_subnet_price
35073571
When safe_staking is enabled, the swap will only execute if:
35083572
- With allow_partial_stake=False: The entire swap amount can be executed without the price ratio
3509-
increasing more than rate_threshold
3573+
increasing more than rate_tolerance
35103574
- With allow_partial_stake=True: A partial amount will be swapped up to the point where the
3511-
price ratio would increase by rate_threshold
3575+
price ratio would increase by rate_tolerance
35123576
"""
35133577
amount = check_and_convert_to_balance(amount)
35143578
return await swap_stake_extrinsic(
@@ -3522,7 +3586,7 @@ async def swap_stake(
35223586
wait_for_finalization=wait_for_finalization,
35233587
safe_staking=safe_staking,
35243588
allow_partial_stake=allow_partial_stake,
3525-
rate_threshold=rate_threshold,
3589+
rate_tolerance=rate_tolerance,
35263590
)
35273591

35283592
async def transfer_stake(
@@ -3613,7 +3677,7 @@ async def unstake(
36133677
wait_for_finalization: bool = False,
36143678
safe_staking: bool = False,
36153679
allow_partial_stake: bool = False,
3616-
rate_threshold: float = 0.005,
3680+
rate_tolerance: float = 0.005,
36173681
) -> bool:
36183682
"""
36193683
Removes a specified amount of stake from a single hotkey account. This function is critical for adjusting
@@ -3628,11 +3692,11 @@ async def unstake(
36283692
wait_for_inclusion (bool): Waits for the transaction to be included in a block.
36293693
wait_for_finalization (bool): Waits for the transaction to be finalized on the blockchain.
36303694
safe_staking (bool): If true, enables price safety checks to protect against fluctuating prices. The unstake
3631-
will only execute if the price change doesn't exceed the rate threshold. Default is False.
3695+
will only execute if the price change doesn't exceed the rate tolerance. Default is False.
36323696
allow_partial_stake (bool): If true and safe_staking is enabled, allows partial unstaking when
36333697
the full amount would exceed the price threshold. If false, the entire unstake fails if it would
36343698
exceed the threshold. Default is False.
3635-
rate_threshold (float): The maximum allowed price change ratio when unstaking. For example,
3699+
rate_tolerance (float): The maximum allowed price change ratio when unstaking. For example,
36363700
0.005 = 0.5% maximum price decrease. Only used when safe_staking is True. Default is 0.005.
36373701
36383702
Returns:
@@ -3652,7 +3716,7 @@ async def unstake(
36523716
wait_for_finalization=wait_for_finalization,
36533717
safe_staking=safe_staking,
36543718
allow_partial_stake=allow_partial_stake,
3655-
rate_threshold=rate_threshold,
3719+
rate_tolerance=rate_tolerance,
36563720
)
36573721

36583722
async def unstake_multiple(

0 commit comments

Comments
 (0)