Skip to content

Commit 560bf29

Browse files
authored
Merge pull request #2560 from opentensor/feat/roman/add-async-commit_reveal
[SDK] Add async version of commit reveal v3
2 parents f4d5ed6 + 71b0c28 commit 560bf29

File tree

5 files changed

+570
-10
lines changed

5 files changed

+570
-10
lines changed

bittensor/core/async_subtensor.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
SubnetHyperparameters,
2323
decode_account_id,
2424
)
25+
from bittensor.core.extrinsics.async_commit_reveal import commit_reveal_v3_extrinsic
2526
from bittensor.core.extrinsics.async_registration import register_extrinsic
2627
from bittensor.core.extrinsics.async_root import (
2728
set_root_weights_extrinsic,
@@ -1596,18 +1597,44 @@ async def set_weights(
15961597
15971598
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】.
15981599
"""
1600+
retries = 0
1601+
success = False
1602+
if (
1603+
uid := await self.get_uid_for_hotkey_on_subnet(
1604+
wallet.hotkey.ss58_address, netuid
1605+
)
1606+
) is None:
1607+
return (
1608+
False,
1609+
f"Hotkey {wallet.hotkey.ss58_address} not registered in subnet {netuid}",
1610+
)
1611+
15991612
if (await self.commit_reveal_enabled(netuid=netuid)) is True:
16001613
# go with `commit reveal v3` extrinsic
1601-
raise NotImplementedError(
1602-
"Not implemented yet for AsyncSubtensor. Coming soon."
1603-
)
1614+
message = "No attempt made. Perhaps it is too soon to commit weights!"
1615+
while (
1616+
await self.blocks_since_last_update(netuid, uid)
1617+
> await self.weights_rate_limit(netuid)
1618+
and retries < max_retries
1619+
and success is False
1620+
):
1621+
logging.info(
1622+
f"Committing weights for subnet #{netuid}. Attempt {retries + 1} of {max_retries}."
1623+
)
1624+
success, message = await commit_reveal_v3_extrinsic(
1625+
subtensor=self,
1626+
wallet=wallet,
1627+
netuid=netuid,
1628+
uids=uids,
1629+
weights=weights,
1630+
version_key=version_key,
1631+
wait_for_inclusion=wait_for_inclusion,
1632+
wait_for_finalization=wait_for_finalization,
1633+
)
1634+
retries += 1
1635+
return success, message
16041636
else:
16051637
# go with classic `set weights extrinsic`
1606-
uid = await self.get_uid_for_hotkey_on_subnet(
1607-
wallet.hotkey.ss58_address, netuid
1608-
)
1609-
retries = 0
1610-
success = False
16111638
message = "No attempt made. Perhaps it is too soon to set weights!"
16121639
while (
16131640
retries < max_retries
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
from typing import Optional, Union, TYPE_CHECKING
2+
3+
import numpy as np
4+
from bittensor_commit_reveal import get_encrypted_commit
5+
from numpy.typing import NDArray
6+
7+
from bittensor.core.settings import version_as_int
8+
from bittensor.utils import format_error_message
9+
from bittensor.utils.btlogging import logging
10+
from bittensor.utils.weight_utils import convert_weights_and_uids_for_emit
11+
12+
if TYPE_CHECKING:
13+
from bittensor_wallet import Wallet
14+
from bittensor.core.async_subtensor import AsyncSubtensor
15+
from bittensor.utils.registration import torch
16+
17+
18+
async def _do_commit_reveal_v3(
19+
subtensor: "AsyncSubtensor",
20+
wallet: "Wallet",
21+
netuid: int,
22+
commit: bytes,
23+
reveal_round: int,
24+
wait_for_inclusion: bool = False,
25+
wait_for_finalization: bool = False,
26+
) -> tuple[bool, Optional[str]]:
27+
"""
28+
Executes the commit-reveal phase 3 for a given netuid and commit, and optionally waits for extrinsic inclusion or finalization.
29+
30+
Arguments:
31+
subtensor: An instance of the Subtensor class.
32+
wallet: Wallet An instance of the Wallet class containing the user's keypair.
33+
netuid: int The network unique identifier.
34+
commit bytes The commit data in bytes format.
35+
reveal_round: int The round number for the reveal phase.
36+
wait_for_inclusion: bool, optional Flag indicating whether to wait for the extrinsic to be included in a block.
37+
wait_for_finalization: bool, optional Flag indicating whether to wait for the extrinsic to be finalized.
38+
39+
Returns:
40+
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.
41+
"""
42+
logging.info(
43+
f"Committing weights hash [blue]{commit.hex()}[/blue] for subnet #[blue]{netuid}[/blue] with "
44+
f"reveal round [blue]{reveal_round}[/blue]..."
45+
)
46+
47+
call = await subtensor.substrate.compose_call(
48+
call_module="SubtensorModule",
49+
call_function="commit_crv3_weights",
50+
call_params={
51+
"netuid": netuid,
52+
"commit": commit,
53+
"reveal_round": reveal_round,
54+
},
55+
)
56+
extrinsic = await subtensor.substrate.create_signed_extrinsic(
57+
call=call,
58+
keypair=wallet.hotkey,
59+
)
60+
61+
response = await subtensor.substrate.submit_extrinsic(
62+
subtensor=subtensor,
63+
extrinsic=extrinsic,
64+
wait_for_inclusion=wait_for_inclusion,
65+
wait_for_finalization=wait_for_finalization,
66+
)
67+
68+
if not wait_for_finalization and not wait_for_inclusion:
69+
return True, "Not waiting for finalization or inclusion."
70+
71+
if await response.is_success:
72+
return True, None
73+
74+
return False, format_error_message(await response.error_message)
75+
76+
77+
async def commit_reveal_v3_extrinsic(
78+
subtensor: "AsyncSubtensor",
79+
wallet: "Wallet",
80+
netuid: int,
81+
uids: Union[NDArray[np.int64], "torch.LongTensor", list],
82+
weights: Union[NDArray[np.float32], "torch.FloatTensor", list],
83+
version_key: int = version_as_int,
84+
wait_for_inclusion: bool = False,
85+
wait_for_finalization: bool = False,
86+
) -> tuple[bool, str]:
87+
"""
88+
Commits and reveals weights for given subtensor and wallet with provided uids and weights.
89+
90+
Arguments:
91+
subtensor: The Subtensor instance.
92+
wallet: The wallet to use for committing and revealing.
93+
netuid: The id of the network.
94+
uids: The uids to commit.
95+
weights: The weights associated with the uids.
96+
version_key: The version key to use for committing and revealing. Default is version_as_int.
97+
wait_for_inclusion: Whether to wait for the inclusion of the transaction. Default is False.
98+
wait_for_finalization: Whether to wait for the finalization of the transaction. Default is False.
99+
100+
Returns:
101+
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.
102+
"""
103+
try:
104+
# Convert uids and weights
105+
if isinstance(uids, list):
106+
uids = np.array(uids, dtype=np.int64)
107+
if isinstance(weights, list):
108+
weights = np.array(weights, dtype=np.float32)
109+
110+
# Reformat and normalize.
111+
uids, weights = convert_weights_and_uids_for_emit(uids, weights)
112+
113+
current_block = await subtensor.substrate.get_block_number(None)
114+
subnet_hyperparameters = await subtensor.get_subnet_hyperparameters(netuid)
115+
tempo = subnet_hyperparameters.tempo
116+
subnet_reveal_period_epochs = (
117+
subnet_hyperparameters.commit_reveal_weights_interval
118+
)
119+
120+
# Encrypt `commit_hash` with t-lock and `get reveal_round`
121+
commit_for_reveal, reveal_round = get_encrypted_commit(
122+
uids=uids,
123+
weights=weights,
124+
version_key=version_key,
125+
tempo=tempo,
126+
current_block=current_block,
127+
netuid=netuid,
128+
subnet_reveal_period_epochs=subnet_reveal_period_epochs,
129+
)
130+
131+
success, message = await _do_commit_reveal_v3(
132+
subtensor=subtensor,
133+
wallet=wallet,
134+
netuid=netuid,
135+
commit=commit_for_reveal,
136+
reveal_round=reveal_round,
137+
wait_for_inclusion=wait_for_inclusion,
138+
wait_for_finalization=wait_for_finalization,
139+
)
140+
141+
if success is not True:
142+
logging.error(message)
143+
return False, message
144+
145+
logging.success(
146+
f"[green]Finalized![/green] Weights commited with reveal round [blue]{reveal_round}[/blue]."
147+
)
148+
return True, f"reveal_round:{reveal_round}"
149+
150+
except Exception as e:
151+
logging.error(f":cross_mark: [red]Failed. Error:[/red] {e}")
152+
return False, str(e)

bittensor/core/subtensor.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,13 @@ def set_weights(
18361836
"""
18371837
retries = 0
18381838
success = False
1839-
uid = self.get_uid_for_hotkey_on_subnet(wallet.hotkey.ss58_address, netuid)
1839+
if (
1840+
uid := self.get_uid_for_hotkey_on_subnet(wallet.hotkey.ss58_address, netuid)
1841+
) is None:
1842+
return (
1843+
False,
1844+
f"Hotkey {wallet.hotkey.ss58_address} not registered in subnet {netuid}",
1845+
)
18401846

18411847
if self.commit_reveal_enabled(netuid=netuid) is True:
18421848
# go with `commit reveal v3` extrinsic

0 commit comments

Comments
 (0)