Skip to content
76 changes: 47 additions & 29 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
swap_stake_extrinsic,
move_stake_extrinsic,
)
from bittensor.core.extrinsics.asyncex.children import (
root_set_pending_childkey_cooldown_extrinsic,
set_children_extrinsic,
)
from bittensor.core.extrinsics.asyncex.registration import (
burned_register_extrinsic,
register_extrinsic,
Expand Down Expand Up @@ -84,13 +88,11 @@
from bittensor.utils import (
Certificate,
decode_hex_identity_dict,
float_to_u64,
format_error_message,
is_valid_ss58_address,
torch,
u16_normalized_float,
u64_normalized_float,
unlock_key,
)
from bittensor.utils.balance import (
Balance,
Expand Down Expand Up @@ -3878,6 +3880,41 @@ async def reveal_weights(

return success, message

async def root_set_pending_childkey_cooldown(
self,
wallet: "Wallet",
cooldown: int,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = True,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""Sets the pending childkey cooldown.

Arguments:
wallet: bittensor wallet instance.
cooldown: the number of blocks to setting pending childkey cooldown.
wait_for_inclusion (bool): Waits for the transaction to be included in a block. Default is ``False``.
wait_for_finalization (bool): Waits for the transaction to be finalized on the blockchain. Default is
``False``.
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.

Returns:
tuple[bool, str]: A tuple where the first element is a boolean indicating success or failure of the
operation, and the second element is a message providing additional information.

Note: This operation can only be successfully performed if your wallet has root privileges.
"""
return await root_set_pending_childkey_cooldown_extrinsic(
subtensor=self,
wallet=wallet,
cooldown=cooldown,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
)

# TODO: remove `block_hash` argument
async def root_register(
self,
Expand Down Expand Up @@ -3998,33 +4035,14 @@ async def set_children(
bittensor_wallet.errors.KeyFileError: Failed to decode keyfile data.
bittensor_wallet.errors.PasswordError: Decryption failed or wrong password for decryption provided.
"""

unlock = unlock_key(wallet, raise_error=raise_error)

if not unlock.success:
return False, unlock.message

call = await self.substrate.compose_call(
call_module="SubtensorModule",
call_function="set_children",
call_params={
"children": [
(
float_to_u64(proportion),
child_hotkey,
)
for proportion, child_hotkey in children
],
"hotkey": hotkey,
"netuid": netuid,
},
)

return await self.sign_and_send_extrinsic(
call,
wallet,
wait_for_inclusion,
wait_for_finalization,
return await set_children_extrinsic(
subtensor=self,
wallet=wallet,
hotkey=hotkey,
netuid=netuid,
children=children,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
raise_error=raise_error,
period=period,
)
Expand Down
139 changes: 139 additions & 0 deletions bittensor/core/extrinsics/asyncex/children.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
from typing import TYPE_CHECKING, Optional
from bittensor.utils import float_to_u64, unlock_key

if TYPE_CHECKING:
from bittensor_wallet import Wallet
from bittensor.core.async_subtensor import AsyncSubtensor


async def set_children_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
hotkey: str,
netuid: int,
children: list[tuple[float, str]],
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
raise_error: bool = False,
period: Optional[int] = None,
):
"""
Allows a coldkey to set children-keys.

Arguments:
subtensor: bittensor subtensor.
wallet: bittensor wallet instance.
hotkey: The ``SS58`` address of the neuron's hotkey.
netuid: The netuid value.
children: A list of children with their proportions.
wait_for_inclusion: Waits for the transaction to be included in a block.
wait_for_finalization: Waits for the transaction to be finalized on the blockchain.
raise_error: Raises a relevant exception rather than returning `False` if unsuccessful.
period: 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.

Returns:
tuple[bool, str]: A tuple where the first element is a boolean indicating success or failure of the operation,
and the second element is a message providing additional information.

Raises:
DuplicateChild: There are duplicates in the list of children.
InvalidChild: Child is the hotkey.
NonAssociatedColdKey: The coldkey does not own the hotkey or the child is the same as the hotkey.
NotEnoughStakeToSetChildkeys: Parent key doesn't have minimum own stake.
ProportionOverflow: The sum of the proportions does exceed uint64.
RegistrationNotPermittedOnRootSubnet: Attempting to register a child on the root network.
SubNetworkDoesNotExist: Attempting to register to a non-existent network.
TooManyChildren: Too many children in request.
TxRateLimitExceeded: Hotkey hit the rate limit.
bittensor_wallet.errors.KeyFileError: Failed to decode keyfile data.
bittensor_wallet.errors.PasswordError: Decryption failed or wrong password for decryption provided.
"""
unlock = unlock_key(wallet, raise_error=raise_error)

if not unlock.success:
return False, unlock.message

async with subtensor.substrate as substrate:
call = await substrate.compose_call(
call_module="SubtensorModule",
call_function="set_children",
call_params={
"children": [
(
float_to_u64(proportion),
child_hotkey,
)
for proportion, child_hotkey in children
],
"hotkey": hotkey,
"netuid": netuid,
},
)

success, message = await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
raise_error=raise_error,
period=period,
)

if not wait_for_finalization and not wait_for_inclusion:
return True, message

if success:
return True, "Success with `set_children_extrinsic` response."

return True, message


async def root_set_pending_childkey_cooldown_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
cooldown: int,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""
Allows a coldkey to set children-keys.
"""
unlock = unlock_key(wallet)

if not unlock.success:
return False, unlock.message

async with subtensor.substrate as substrate:
call = await substrate.compose_call(
call_module="SubtensorModule",
call_function="set_pending_childkey_cooldown",
call_params={"cooldown": cooldown},
)

sudo_call = await substrate.compose_call(
call_module="Sudo",
call_function="sudo",
call_params={"call": call},
)

success, message = await subtensor.sign_and_send_extrinsic(
call=sudo_call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
)

if not wait_for_finalization and not wait_for_inclusion:
return True, message

if success:
return (
True,
"Success with `root_set_pending_childkey_cooldown_extrinsic` response.",
)

return True, message
137 changes: 137 additions & 0 deletions bittensor/core/extrinsics/children.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from typing import TYPE_CHECKING, Optional
from bittensor.utils import float_to_u64, unlock_key

if TYPE_CHECKING:
from bittensor_wallet import Wallet
from bittensor.core.subtensor import Subtensor


def set_children_extrinsic(
subtensor: "Subtensor",
wallet: "Wallet",
hotkey: str,
netuid: int,
children: list[tuple[float, str]],
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
raise_error: bool = False,
period: Optional[int] = None,
):
"""
Allows a coldkey to set children-keys.

Arguments:
subtensor: bittensor subtensor.
wallet: bittensor wallet instance.
hotkey: The ``SS58`` address of the neuron's hotkey.
netuid: The netuid value.
children: A list of children with their proportions.
wait_for_inclusion: Waits for the transaction to be included in a block.
wait_for_finalization: Waits for the transaction to be finalized on the blockchain.
raise_error: Raises a relevant exception rather than returning `False` if unsuccessful.
period: 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.

Returns:
tuple[bool, str]: A tuple where the first element is a boolean indicating success or failure of the operation,
and the second element is a message providing additional information.

Raises:
DuplicateChild: There are duplicates in the list of children.
InvalidChild: Child is the hotkey.
NonAssociatedColdKey: The coldkey does not own the hotkey or the child is the same as the hotkey.
NotEnoughStakeToSetChildkeys: Parent key doesn't have minimum own stake.
ProportionOverflow: The sum of the proportions does exceed uint64.
RegistrationNotPermittedOnRootSubnet: Attempting to register a child on the root network.
SubNetworkDoesNotExist: Attempting to register to a non-existent network.
TooManyChildren: Too many children in request.
TxRateLimitExceeded: Hotkey hit the rate limit.
bittensor_wallet.errors.KeyFileError: Failed to decode keyfile data.
bittensor_wallet.errors.PasswordError: Decryption failed or wrong password for decryption provided.
"""
unlock = unlock_key(wallet, raise_error=raise_error)

if not unlock.success:
return False, unlock.message

call = subtensor.substrate.compose_call(
call_module="SubtensorModule",
call_function="set_children",
call_params={
"children": [
(
float_to_u64(proportion),
child_hotkey,
)
for proportion, child_hotkey in children
],
"hotkey": hotkey,
"netuid": netuid,
},
)

success, message = subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
raise_error=raise_error,
period=period,
)

if not wait_for_finalization and not wait_for_inclusion:
return True, message

if success:
return True, "Success with `set_children_extrinsic` response."

return True, message


def root_set_pending_childkey_cooldown_extrinsic(
subtensor: "Subtensor",
wallet: "Wallet",
cooldown: int,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
) -> tuple[bool, str]:
"""
Allows a coldkey to set children-keys.
"""
unlock = unlock_key(wallet)

if not unlock.success:
return False, unlock.message

call = subtensor.substrate.compose_call(
call_module="SubtensorModule",
call_function="set_pending_childkey_cooldown",
call_params={"cooldown": cooldown},
)

sudo_call = subtensor.substrate.compose_call(
call_module="Sudo",
call_function="sudo",
call_params={"call": call},
)

success, message = subtensor.sign_and_send_extrinsic(
call=sudo_call,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
)

if not wait_for_finalization and not wait_for_inclusion:
return True, message

if success:
return (
True,
"Success with `root_set_pending_childkey_cooldown_extrinsic` response.",
)

return True, message
Loading