Skip to content

Commit

Permalink
Merge branch 'staging' into patch-2
Browse files Browse the repository at this point in the history
  • Loading branch information
thewhaleking authored Jan 13, 2025
2 parents 5a22780 + b3c0ab7 commit 66cd437
Show file tree
Hide file tree
Showing 19 changed files with 1,055 additions and 50 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ LABEL bittensor.image.authors="bittensor.com" \
ARG DEBIAN_FRONTEND=noninteractive

# Update the base image
RUN apt update && apt upgrade -y
RUN apt-get update && apt-get upgrade -y
# Install bittensor
## Install dependencies
RUN apt install -y curl sudo nano git htop netcat-openbsd wget unzip tmux apt-utils cmake build-essential
RUN apt-get install -y curl sudo nano git htop netcat-openbsd wget unzip tmux apt-utils cmake build-essential
## Upgrade pip
RUN pip3 install --upgrade pip

Expand Down
43 changes: 35 additions & 8 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
SubnetHyperparameters,
decode_account_id,
)
from bittensor.core.extrinsics.async_commit_reveal import commit_reveal_v3_extrinsic
from bittensor.core.extrinsics.async_registration import register_extrinsic
from bittensor.core.extrinsics.async_root import (
set_root_weights_extrinsic,
Expand Down Expand Up @@ -1596,18 +1597,44 @@ async def set_weights(
This function is crucial in shaping the network's collective intelligence, where each neuron's learning and contribution are influenced by the weights it sets towards others【81†source】.
"""
retries = 0
success = False
if (
uid := await self.get_uid_for_hotkey_on_subnet(
wallet.hotkey.ss58_address, netuid
)
) is None:
return (
False,
f"Hotkey {wallet.hotkey.ss58_address} not registered in subnet {netuid}",
)

if (await self.commit_reveal_enabled(netuid=netuid)) is True:
# go with `commit reveal v3` extrinsic
raise NotImplementedError(
"Not implemented yet for AsyncSubtensor. Coming soon."
)
message = "No attempt made. Perhaps it is too soon to commit weights!"
while (
await self.blocks_since_last_update(netuid, uid)
> await self.weights_rate_limit(netuid)
and retries < max_retries
and success is False
):
logging.info(
f"Committing weights for subnet #{netuid}. Attempt {retries + 1} of {max_retries}."
)
success, message = await commit_reveal_v3_extrinsic(
subtensor=self,
wallet=wallet,
netuid=netuid,
uids=uids,
weights=weights,
version_key=version_key,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)
retries += 1
return success, message
else:
# go with classic `set weights extrinsic`
uid = await self.get_uid_for_hotkey_on_subnet(
wallet.hotkey.ss58_address, netuid
)
retries = 0
success = False
message = "No attempt made. Perhaps it is too soon to set weights!"
while (
retries < max_retries
Expand Down
152 changes: 152 additions & 0 deletions bittensor/core/extrinsics/async_commit_reveal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from typing import Optional, Union, TYPE_CHECKING

import numpy as np
from bittensor_commit_reveal import get_encrypted_commit
from numpy.typing import NDArray

from bittensor.core.settings import version_as_int
from bittensor.utils import format_error_message
from bittensor.utils.btlogging import logging
from bittensor.utils.weight_utils import convert_weights_and_uids_for_emit

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


async def _do_commit_reveal_v3(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
netuid: int,
commit: bytes,
reveal_round: int,
wait_for_inclusion: bool = False,
wait_for_finalization: bool = False,
) -> tuple[bool, Optional[str]]:
"""
Executes the commit-reveal phase 3 for a given netuid and commit, and optionally waits for extrinsic inclusion or finalization.
Arguments:
subtensor: An instance of the Subtensor class.
wallet: Wallet An instance of the Wallet class containing the user's keypair.
netuid: int The network unique identifier.
commit bytes The commit data in bytes format.
reveal_round: int The round number for the reveal phase.
wait_for_inclusion: bool, optional Flag indicating whether to wait for the extrinsic to be included in a block.
wait_for_finalization: bool, optional Flag indicating whether to wait for the extrinsic to be finalized.
Returns:
A tuple where the first element is a boolean indicating success or failure, and the second element is an optional string containing error message if any.
"""
logging.info(
f"Committing weights hash [blue]{commit.hex()}[/blue] for subnet #[blue]{netuid}[/blue] with "
f"reveal round [blue]{reveal_round}[/blue]..."
)

call = await subtensor.substrate.compose_call(
call_module="SubtensorModule",
call_function="commit_crv3_weights",
call_params={
"netuid": netuid,
"commit": commit,
"reveal_round": reveal_round,
},
)
extrinsic = await subtensor.substrate.create_signed_extrinsic(
call=call,
keypair=wallet.hotkey,
)

response = await subtensor.substrate.submit_extrinsic(
subtensor=subtensor,
extrinsic=extrinsic,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)

if not wait_for_finalization and not wait_for_inclusion:
return True, "Not waiting for finalization or inclusion."

if await response.is_success:
return True, None

return False, format_error_message(await response.error_message)


async def commit_reveal_v3_extrinsic(
subtensor: "AsyncSubtensor",
wallet: "Wallet",
netuid: int,
uids: Union[NDArray[np.int64], "torch.LongTensor", list],
weights: Union[NDArray[np.float32], "torch.FloatTensor", list],
version_key: int = version_as_int,
wait_for_inclusion: bool = False,
wait_for_finalization: bool = False,
) -> tuple[bool, str]:
"""
Commits and reveals weights for given subtensor and wallet with provided uids and weights.
Arguments:
subtensor: The Subtensor instance.
wallet: The wallet to use for committing and revealing.
netuid: The id of the network.
uids: The uids to commit.
weights: The weights associated with the uids.
version_key: The version key to use for committing and revealing. Default is version_as_int.
wait_for_inclusion: Whether to wait for the inclusion of the transaction. Default is False.
wait_for_finalization: Whether to wait for the finalization of the transaction. Default is False.
Returns:
tuple[bool, str]: A tuple where the first element is a boolean indicating success or failure, and the second element is a message associated with the result.
"""
try:
# Convert uids and weights
if isinstance(uids, list):
uids = np.array(uids, dtype=np.int64)
if isinstance(weights, list):
weights = np.array(weights, dtype=np.float32)

# Reformat and normalize.
uids, weights = convert_weights_and_uids_for_emit(uids, weights)

current_block = await subtensor.substrate.get_block_number(None)
subnet_hyperparameters = await subtensor.get_subnet_hyperparameters(netuid)
tempo = subnet_hyperparameters.tempo
subnet_reveal_period_epochs = (
subnet_hyperparameters.commit_reveal_weights_interval
)

# Encrypt `commit_hash` with t-lock and `get reveal_round`
commit_for_reveal, reveal_round = get_encrypted_commit(
uids=uids,
weights=weights,
version_key=version_key,
tempo=tempo,
current_block=current_block,
netuid=netuid,
subnet_reveal_period_epochs=subnet_reveal_period_epochs,
)

success, message = await _do_commit_reveal_v3(
subtensor=subtensor,
wallet=wallet,
netuid=netuid,
commit=commit_for_reveal,
reveal_round=reveal_round,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)

if success is not True:
logging.error(message)
return False, message

logging.success(
f"[green]Finalized![/green] Weights commited with reveal round [blue]{reveal_round}[/blue]."
)
return True, f"reveal_round:{reveal_round}"

except Exception as e:
logging.error(f":cross_mark: [red]Failed. Error:[/red] {e}")
return False, str(e)
12 changes: 12 additions & 0 deletions bittensor/core/extrinsics/async_weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,17 @@ async def _do_set_weights(
"version_key": version_key,
},
)

next_nonce = await subtensor.substrate.get_account_next_index(
wallet.hotkey.ss58_address
)

# Period dictates how long the extrinsic will stay as part of waiting pool
extrinsic = await subtensor.substrate.create_signed_extrinsic(
call=call,
keypair=wallet.hotkey,
era={"period": 5},
nonce=next_nonce,
)
response = await subtensor.substrate.submit_extrinsic(
extrinsic,
Expand Down Expand Up @@ -180,9 +186,15 @@ async def _do_commit_weights(
"commit_hash": commit_hash,
},
)

next_nonce = await subtensor.substrate.get_account_next_index(
wallet.hotkey.ss58_address
)

extrinsic = await subtensor.substrate.create_signed_extrinsic(
call=call,
keypair=wallet.hotkey,
nonce=next_nonce,
)
response = await subtensor.substrate.submit_extrinsic(
substrate=subtensor.substrate,
Expand Down
2 changes: 2 additions & 0 deletions bittensor/core/extrinsics/commit_weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ def do_commit_weights(
"commit_hash": commit_hash,
},
)
next_nonce = self.get_account_next_index(wallet.hotkey.ss58_address)
extrinsic = self.substrate.create_signed_extrinsic(
call=call,
keypair=wallet.hotkey,
nonce=next_nonce,
)
response = submit_extrinsic(
subtensor=self,
Expand Down
2 changes: 2 additions & 0 deletions bittensor/core/extrinsics/set_weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ def do_set_weights(
"version_key": version_key,
},
)
next_nonce = self.get_account_next_index(wallet.hotkey.ss58_address)
# Period dictates how long the extrinsic will stay as part of waiting pool
extrinsic = self.substrate.create_signed_extrinsic(
call=call,
keypair=wallet.hotkey,
era={"period": period},
nonce=next_nonce,
)
response = submit_extrinsic(
self,
Expand Down
40 changes: 33 additions & 7 deletions bittensor/core/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from scalecodec.type_registry import load_type_registry_preset
from scalecodec.types import ScaleType
from substrateinterface.base import QueryMapResult, SubstrateInterface
from websockets.exceptions import InvalidStatus
from websockets.sync import client as ws_client

from bittensor.core import settings
Expand Down Expand Up @@ -233,6 +234,7 @@ def _get_substrate(self, force: bool = False):
open_timeout=self._connection_timeout,
max_size=2**32,
)

self.substrate = SubstrateInterface(
ss58_format=settings.SS58_FORMAT,
use_remote_preset=True,
Expand All @@ -244,19 +246,27 @@ def _get_substrate(self, force: bool = False):
f"Connected to {self.network} network and {self.chain_endpoint}."
)

except (ConnectionRefusedError, ssl.SSLError) as error:
logging.error(
f"<red>Could not connect to</red> <blue>{self.network}</blue> <red>network with</red> <blue>{self.chain_endpoint}</blue> <red>chain endpoint.</red>",
except ConnectionRefusedError as error:
logging.critical(
f"[red]Could not connect to[/red] [blue]{self.network}[/blue] [red]network with[/red] [blue]{self.chain_endpoint}[/blue] [red]chain endpoint.[/red]",
)
raise ConnectionRefusedError(error.args)
except ssl.SSLError as e:

except ssl.SSLError as error:
logging.critical(
"SSL error occurred. To resolve this issue, run the following command in your terminal:"
)
logging.critical("[blue]sudo python -m bittensor certifi[/blue]")
raise RuntimeError(
"SSL configuration issue, please follow the instructions above."
) from e
) from error

except InvalidStatus as error:
logging.critical(
f"Error [red]'{error.response.reason_phrase}'[/red] with status code [red]{error.response.status_code}[/red]."
)
logging.debug(f"Server response is '{error.response}'.")
raise

@staticmethod
def config() -> "Config":
Expand Down Expand Up @@ -661,6 +671,16 @@ def query_module(
),
)

@networking.ensure_connected
def get_account_next_index(self, address: str) -> int:
"""
Returns the next nonce for an account, taking into account the transaction pool.
"""
if not self.substrate.supports_rpc_method("account_nextIndex"):
raise Exception("account_nextIndex not supported")

return self.substrate.rpc_request("account_nextIndex", [address])["result"]

# Common subtensor methods =========================================================================================
def metagraph(
self, netuid: int, lite: bool = True, block: Optional[int] = None
Expand Down Expand Up @@ -1764,7 +1784,7 @@ def get_delegates(self, block: Optional[int] = None) -> list[DelegateInfo]:
if not (result := json_body.get("result", None)):
return []

return DelegateInfo.list_from_vec_u8(result)
return DelegateInfo.list_from_vec_u8(bytes(result))

def is_hotkey_delegate(self, hotkey_ss58: str, block: Optional[int] = None) -> bool:
"""
Expand Down Expand Up @@ -1816,7 +1836,13 @@ def set_weights(
"""
retries = 0
success = False
uid = self.get_uid_for_hotkey_on_subnet(wallet.hotkey.ss58_address, netuid)
if (
uid := self.get_uid_for_hotkey_on_subnet(wallet.hotkey.ss58_address, netuid)
) is None:
return (
False,
f"Hotkey {wallet.hotkey.ss58_address} not registered in subnet {netuid}",
)

if self.commit_reveal_enabled(netuid=netuid) is True:
# go with `commit reveal v3` extrinsic
Expand Down
Loading

0 comments on commit 66cd437

Please sign in to comment.