Skip to content

Commit

Permalink
Merge pull request #1938 from opentensor/feature/opendansor/commit_we…
Browse files Browse the repository at this point in the history
…ights

Add commit weights and reveal weights functions
  • Loading branch information
opendansor authored and gus-opentensor committed Jun 5, 2024
1 parent f352f71 commit 2b2c039
Show file tree
Hide file tree
Showing 12 changed files with 1,201 additions and 6 deletions.
6 changes: 6 additions & 0 deletions bittensor/chain_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@
["max_validators", "Compact<u16>"],
["adjustment_alpha", "Compact<u64>"],
["difficulty", "Compact<u64>"],
["commit_reveal_weights_interval", "Compact<u64>"],
["commit_reveal_weights_enabled", "bool"],
],
},
}
Expand Down Expand Up @@ -1045,6 +1047,8 @@ class SubnetHyperparameters:
max_validators: int
adjustment_alpha: int
difficulty: int
commit_reveal_weights_interval: int
commit_reveal_weights_enabled: bool

@classmethod
def from_vec_u8(cls, vec_u8: List[int]) -> Optional["SubnetHyperparameters"]:
Expand Down Expand Up @@ -1099,6 +1103,8 @@ def fix_decoded_values(cls, decoded: Dict) -> "SubnetHyperparameters":
bonds_moving_avg=decoded["bonds_moving_avg"],
adjustment_alpha=decoded["adjustment_alpha"],
difficulty=decoded["difficulty"],
commit_reveal_weights_interval=decoded["commit_reveal_weights_interval"],
commit_reveal_weights_enabled=decoded["commit_reveal_weights_enabled"],
)

def _to_parameter_dict_torch(
Expand Down
14 changes: 14 additions & 0 deletions bittensor/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
VoteCommand,
WalletBalanceCommand,
WalletCreateCommand,
CommitWeightCommand,
RevealWeightCommand,
)

# Create a console instance for CLI display.
Expand All @@ -92,6 +94,9 @@
"sudos": "sudo",
"i": "info",
"info": "info",
"weights": "weights",
"wt": "weights",
"weight": "weights",
}
COMMANDS = {
"subnets": {
Expand Down Expand Up @@ -164,6 +169,15 @@
"remove": UnStakeCommand,
},
},
"weights": {
"name": "weights",
"aliases": ["wt", "weight"],
"help": "Commands for managing weight for subnets.",
"commands": {
"commit": CommitWeightCommand,
"reveal": RevealWeightCommand,
},
},
"sudo": {
"name": "sudo",
"aliases": ["su", "sudos"],
Expand Down
1 change: 1 addition & 0 deletions bittensor/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
WalletBalanceCommand,
GetWalletHistoryCommand,
)
from .weights import CommitWeightCommand, RevealWeightCommand
from .transfer import TransferCommand
from .inspect import InspectCommand
from .metagraph import MetagraphCommand
Expand Down
2 changes: 2 additions & 0 deletions bittensor/commands/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ def add_args(parser: argparse.ArgumentParser):
"kappa": "sudo_set_kappa",
"difficulty": "sudo_set_difficulty",
"bonds_moving_avg": "sudo_set_bonds_moving_average",
"commit_reveal_weights_interval": "sudo_set_commit_reveal_weights_interval",
"commit_reveal_weights_enabled": "sudo_set_commit_reveal_weights_enabled",
}


Expand Down
284 changes: 284 additions & 0 deletions bittensor/commands/weights.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
# The MIT License (MIT)
# Copyright © 2021 Yuma Rao
# Copyright © 2023 Opentensor Foundation

# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
# the Software.

# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

"""Module that encapsulates the CommitWeightCommand and the RevealWeightCommand. Used to commit and reveal weights
for a specific subnet on the Bittensor Network."""


import argparse
import os
import re

import numpy as np
from rich.prompt import Prompt, Confirm
import bittensor.utils.weight_utils as weight_utils
import bittensor
from . import defaults # type: ignore


class CommitWeightCommand:
"""
Executes the ``commit`` command to commit weights for specific subnet on the Bittensor network.
Usage:
The command allows committing weights for a specific subnet. Users need to specify the netuid (network unique identifier), corresponding UIDs, and weights they wish to commit.
Optional arguments:
- ``--netuid`` (int): The netuid of the subnet for which weights are to be commited.
- ``--uids`` (str): Corresponding UIDs for the specified netuid, in comma-separated format.
- ``--weights`` (str): Corresponding weights for the specified UIDs, in comma-separated format.
Example usage:
$ btcli wt commit --netuid 1 --uids 1,2,3,4 --weights 0.1,0.2,0.3,0.4
Note:
This command is used to commit weights for a specific subnet and requires the user to have the necessary permissions.
"""

@staticmethod
def run(cli: "bittensor.cli"):
r"""Commit weights for a specific subnet."""
try:
subtensor: "bittensor.subtensor" = bittensor.subtensor(
config=cli.config, log_verbose=False
)
CommitWeightCommand._run(cli, subtensor)
finally:
if "subtensor" in locals():
subtensor.close()
bittensor.logging.debug("closing subtensor connection")

@staticmethod
def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
r"""Commit weights for a specific subnet"""
wallet = bittensor.wallet(config=cli.config)

# Get values if not set
if not cli.config.is_set("netuid"):
cli.config.netuid = int(Prompt.ask(f"Enter netuid"))

if not cli.config.is_set("uids"):
cli.config.uids = Prompt.ask(f"Enter UIDs (comma-separated)")

if not cli.config.is_set("weights"):
cli.config.weights = Prompt.ask(f"Enter weights (comma-separated)")

# Parse from string
netuid = cli.config.netuid
uids = np.array(
[int(x) for x in re.split(r"[ ,]+", cli.config.uids)], dtype=np.int64
)
weights = np.array(
[float(x) for x in re.split(r"[ ,]+", cli.config.weights)], dtype=np.float32
)
weight_uids, weight_vals = weight_utils.convert_weights_and_uids_for_emit(
uids=uids, weights=weights
)

# Generate random salt
salt_length = 8
salt = list(os.urandom(salt_length))

if not Confirm.ask(
f"Have you recorded the [red]salt[/red]: [bold white]'{salt}'[/bold white]? It will be "
f"required to reveal weights."
):
return False, "User cancelled the operation."

# Run the commit weights operation
success, message = subtensor.commit_weights(
wallet=wallet,
netuid=netuid,
uids=weight_uids,
weights=weight_vals,
salt=salt,
wait_for_inclusion=cli.config.wait_for_inclusion,
wait_for_finalization=cli.config.wait_for_finalization,
prompt=cli.config.prompt,
)

# Result
if success:
bittensor.__console__.print(f"Weights committed successfully")
else:
bittensor.__console__.print(f"Failed to commit weights: {message}")

@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser(
"commit", help="""Commit weights for a specific subnet."""
)
parser.add_argument("--netuid", dest="netuid", type=int, required=False)
parser.add_argument("--uids", dest="uids", type=str, required=False)
parser.add_argument("--weights", dest="weights", type=str, required=False)
parser.add_argument("--salt", dest="salt", type=str, required=False)
parser.add_argument(
"--wait-for-inclusion",
dest="wait_for_inclusion",
action="store_true",
default=False,
)
parser.add_argument(
"--wait-for-finalization",
dest="wait_for_finalization",
action="store_true",
default=True,
)
parser.add_argument(
"--prompt",
dest="prompt",
action="store_true",
default=False,
)

bittensor.wallet.add_args(parser)
bittensor.subtensor.add_args(parser)

@staticmethod
def check_config(config: "bittensor.config"):
if not config.no_prompt and not config.is_set("wallet.name"):
wallet_name = Prompt.ask("Enter wallet name", default=defaults.wallet.name)
config.wallet.name = str(wallet_name)
if not config.no_prompt and not config.is_set("wallet.hotkey"):
hotkey = Prompt.ask("Enter hotkey name", default=defaults.wallet.hotkey)
config.wallet.hotkey = str(hotkey)


class RevealWeightCommand:
"""
Executes the ``reveal`` command to reveal weights for a specific subnet on the Bittensor network.
Usage:
The command allows revealing weights for a specific subnet. Users need to specify the netuid (network unique identifier), corresponding UIDs, and weights they wish to reveal.
Optional arguments:
- ``--netuid`` (int): The netuid of the subnet for which weights are to be revealed.
- ``--uids`` (str): Corresponding UIDs for the specified netuid, in comma-separated format.
- ``--weights`` (str): Corresponding weights for the specified UIDs, in comma-separated format.
- ``--salt`` (str): Corresponding salt for the hash function, integers in comma-separated format.
Example usage::
$ btcli wt reveal --netuid 1 --uids 1,2,3,4 --weights 0.1,0.2,0.3,0.4 --salt 163,241,217,11,161,142,147,189
Note:
This command is used to reveal weights for a specific subnet and requires the user to have the necessary permissions.
"""

@staticmethod
def run(cli: "bittensor.cli"):
r"""Reveal weights for a specific subnet."""
try:
subtensor: "bittensor.subtensor" = bittensor.subtensor(
config=cli.config, log_verbose=False
)
RevealWeightCommand._run(cli, subtensor)
finally:
if "subtensor" in locals():
subtensor.close()
bittensor.logging.debug("closing subtensor connection")

@staticmethod
def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
r"""Reveal weights for a specific subnet."""
wallet = bittensor.wallet(config=cli.config)

# Get values if not set.
if not cli.config.is_set("netuid"):
cli.config.netuid = int(Prompt.ask(f"Enter netuid"))

if not cli.config.is_set("uids"):
cli.config.uids = Prompt.ask(f"Enter UIDs (comma-separated)")

if not cli.config.is_set("weights"):
cli.config.weights = Prompt.ask(f"Enter weights (comma-separated)")

if not cli.config.is_set("salt"):
cli.config.salt = Prompt.ask(f"Enter salt (comma-separated)")

# Parse from string
netuid = cli.config.netuid
version = bittensor.__version_as_int__
uids = np.array(
[int(x) for x in re.split(r"[ ,]+", cli.config.uids)],
dtype=np.int64,
)
weights = np.array(
[float(x) for x in re.split(r"[ ,]+", cli.config.weights)],
dtype=np.float32,
)
salt = np.array(
[int(x) for x in re.split(r"[ ,]+", cli.config.salt)],
dtype=np.int64,
)
weight_uids, weight_vals = weight_utils.convert_weights_and_uids_for_emit(
uids=uids, weights=weights
)

# Run the reveal weights operation.
success, message = subtensor.reveal_weights(
wallet=wallet,
netuid=netuid,
uids=weight_uids,
weights=weight_vals,
salt=salt,
version_key=version,
wait_for_inclusion=cli.config.wait_for_inclusion,
wait_for_finalization=cli.config.wait_for_finalization,
prompt=cli.config.prompt,
)

if success:
bittensor.__console__.print(f"Weights revealed successfully")
else:
bittensor.__console__.print(f"Failed to reveal weights: {message}")

@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser(
"reveal", help="""Reveal weights for a specific subnet."""
)
parser.add_argument("--netuid", dest="netuid", type=int, required=False)
parser.add_argument("--uids", dest="uids", type=str, required=False)
parser.add_argument("--weights", dest="weights", type=str, required=False)
parser.add_argument("--salt", dest="salt", type=str, required=False)
parser.add_argument(
"--wait-for-inclusion",
dest="wait_for_inclusion",
action="store_true",
default=False,
)
parser.add_argument(
"--wait-for-finalization",
dest="wait_for_finalization",
action="store_true",
default=True,
)
parser.add_argument(
"--prompt",
dest="prompt",
action="store_true",
default=False,
)

bittensor.wallet.add_args(parser)
bittensor.subtensor.add_args(parser)

@staticmethod
def check_config(config: "bittensor.config"):
if not config.is_set("wallet.name") and not config.no_prompt:
wallet_name = Prompt.ask("Enter wallet name", default=defaults.wallet.name)
config.wallet.name = str(wallet_name)
if not config.is_set("wallet.hotkey") and not config.no_prompt:
hotkey = Prompt.ask("Enter hotkey name", default=defaults.wallet.hotkey)
config.wallet.hotkey = str(hotkey)
Loading

0 comments on commit 2b2c039

Please sign in to comment.