Skip to content

Commit 0a7c3ac

Browse files
authored
Merge branch 'staging' into tests/zyzniewski/async_e2e
2 parents 3b9764d + 3e67b6c commit 0a7c3ac

File tree

15 files changed

+536
-22
lines changed

15 files changed

+536
-22
lines changed

.circleci/config.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ workflows:
290290
- check_compatibility:
291291
python_version: "3.12"
292292
name: check-compatibility-3.12
293+
- check_compatibility:
294+
python_version: "3.13"
295+
name: check-compatibility-3.13
293296

294297

295298
pr-requirements:
@@ -302,7 +305,7 @@ workflows:
302305
- build-and-test:
303306
matrix:
304307
parameters:
305-
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7" ]
308+
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7"]
306309
requires:
307310
- check-if-pr-is-draft
308311
- unit-tests-all-python-versions:
@@ -311,7 +314,7 @@ workflows:
311314
- lint-and-type-check:
312315
matrix:
313316
parameters:
314-
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7" ]
317+
python-version: [ "3.9.13", "3.10.6", "3.11.4", "3.12.7"]
315318
requires:
316319
- check-if-pr-is-draft
317320
#- coveralls:

bittensor/core/async_subtensor.py

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@
2727
decode_account_id,
2828
DynamicInfo,
2929
)
30+
from bittensor_commit_reveal import get_encrypted_commitment
3031
from bittensor.core.chain_data.chain_identity import ChainIdentity
3132
from bittensor.core.chain_data.delegate_info import DelegatedInfo
32-
from bittensor.core.chain_data.utils import decode_metadata
33+
from bittensor.core.chain_data.utils import (
34+
decode_metadata,
35+
decode_revealed_commitment,
36+
decode_revealed_commitment_with_hotkey,
37+
)
3338
from bittensor.core.config import Config
3439
from bittensor.core.errors import ChainError, SubstrateRequestException
3540
from bittensor.core.extrinsics.asyncex.commit_reveal import commit_reveal_v3_extrinsic
@@ -1059,6 +1064,68 @@ async def get_all_commitments(
10591064
result[decode_account_id(id_[0])] = decode_metadata(value)
10601065
return result
10611066

1067+
async def get_revealed_commitment(
1068+
self,
1069+
netuid: int,
1070+
hotkey_ss58_address: Optional[str] = None,
1071+
block: Optional[int] = None,
1072+
block_hash: Optional[str] = None,
1073+
reuse_block: bool = False,
1074+
) -> Optional[tuple[int, str]]:
1075+
"""Returns hotkey related revealed commitment for a given netuid.
1076+
1077+
Arguments:
1078+
netuid (int): The unique identifier of the subnetwork.
1079+
block (Optional[int]): The block number to retrieve the commitment from. Default is ``None``.
1080+
hotkey_ss58_address (str): The ss58 address of the committee member.
1081+
block_hash (Optional[str]): The hash of the block to retrieve the subnet unique identifiers from.
1082+
reuse_block (bool): Whether to reuse the last-used block hash.
1083+
1084+
Returns:
1085+
result (tuple[int, str): A tuple of reveal block and commitment message.
1086+
"""
1087+
query = await self.query_module(
1088+
module="Commitments",
1089+
name="RevealedCommitments",
1090+
params=[netuid, hotkey_ss58_address],
1091+
block=block,
1092+
block_hash=block_hash,
1093+
reuse_block=reuse_block,
1094+
)
1095+
return decode_revealed_commitment(query)
1096+
1097+
async def get_all_revealed_commitments(
1098+
self,
1099+
netuid: int,
1100+
block: Optional[int] = None,
1101+
block_hash: Optional[str] = None,
1102+
reuse_block: bool = False,
1103+
) -> dict[str, tuple[int, str]]:
1104+
"""Returns all revealed commitments for a given netuid.
1105+
1106+
Arguments:
1107+
netuid (int): The unique identifier of the subnetwork.
1108+
block (Optional[int]): The block number to retrieve the commitment from. Default is ``None``.
1109+
block_hash (Optional[str]): The hash of the block to retrieve the subnet unique identifiers from.
1110+
reuse_block (bool): Whether to reuse the last-used block hash.
1111+
1112+
Returns:
1113+
result (dict): A dictionary of all revealed commitments in view {ss58_address: (reveal block, commitment message)}.
1114+
"""
1115+
query = await self.query_map(
1116+
module="Commitments",
1117+
name="RevealedCommitments",
1118+
params=[netuid],
1119+
block=block,
1120+
block_hash=block_hash,
1121+
reuse_block=reuse_block,
1122+
)
1123+
1124+
result = {}
1125+
async for item in query:
1126+
result.update(decode_revealed_commitment_with_hotkey(item))
1127+
return result
1128+
10621129
async def get_current_weight_commit_info(
10631130
self,
10641131
netuid: int,
@@ -1572,6 +1639,36 @@ async def get_neuron_for_pubkey_and_subnet(
15721639
reuse_block=reuse_block,
15731640
)
15741641

1642+
async def get_owned_hotkeys(
1643+
self,
1644+
coldkey_ss58: str,
1645+
block: Optional[int] = None,
1646+
block_hash: Optional[str] = None,
1647+
reuse_block: bool = False,
1648+
) -> list[str]:
1649+
"""
1650+
Retrieves all hotkeys owned by a specific coldkey address.
1651+
1652+
Args:
1653+
coldkey_ss58 (str): The SS58 address of the coldkey to query.
1654+
block (int): The blockchain block number for the query.
1655+
block_hash (str): The hash of the blockchain block number for the query.
1656+
reuse_block (bool): Whether to reuse the last-used blockchain block hash.
1657+
1658+
Returns:
1659+
list[str]: A list of hotkey SS58 addresses owned by the coldkey.
1660+
"""
1661+
block_hash = await self.determine_block_hash(block, block_hash, reuse_block)
1662+
owned_hotkeys = await self.substrate.query(
1663+
module="SubtensorModule",
1664+
storage_function="OwnedHotkeys",
1665+
params=[coldkey_ss58],
1666+
block_hash=block_hash,
1667+
reuse_block_hash=reuse_block,
1668+
)
1669+
1670+
return [decode_account_id(hotkey[0]) for hotkey in owned_hotkeys or []]
1671+
15751672
async def get_stake(
15761673
self,
15771674
coldkey_ss58: str,
@@ -2620,6 +2717,46 @@ async def recycle(
26202717
)
26212718
return None if call is None else Balance.from_rao(int(call))
26222719

2720+
async def set_reveal_commitment(
2721+
self,
2722+
wallet,
2723+
netuid: int,
2724+
data: str,
2725+
blocks_until_reveal: int = 360,
2726+
block_time: Union[int, float] = 12,
2727+
) -> tuple[bool, int]:
2728+
"""
2729+
Commits arbitrary data to the Bittensor network by publishing metadata.
2730+
2731+
Arguments:
2732+
wallet (bittensor_wallet.Wallet): The wallet associated with the neuron committing the data.
2733+
netuid (int): The unique identifier of the subnetwork.
2734+
data (str): The data to be committed to the network.
2735+
blocks_until_reveal (int): The number of blocks from now after which the data will be revealed. Defaults to `360`.
2736+
Then amount of blocks in one epoch.
2737+
block_time (Union[int, float]): The number of seconds between each block. Defaults to `12`.
2738+
2739+
Returns:
2740+
bool: `True` if the commitment was successful, `False` otherwise.
2741+
2742+
Note: A commitment can be set once per subnet epoch and is reset at the next epoch in the chain automatically.
2743+
"""
2744+
2745+
encrypted, reveal_round = get_encrypted_commitment(
2746+
data, blocks_until_reveal, block_time
2747+
)
2748+
2749+
# increase reveal_round in return + 1 because we want to fetch data from the chain after that round was revealed
2750+
# and stored.
2751+
data_ = {"encrypted": encrypted, "reveal_round": reveal_round}
2752+
return await publish_metadata(
2753+
subtensor=self,
2754+
wallet=wallet,
2755+
netuid=netuid,
2756+
data_type=f"TimelockEncrypted",
2757+
data=data_,
2758+
), reveal_round
2759+
26232760
async def subnet(
26242761
self,
26252762
netuid: int,

bittensor/core/axon.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,9 @@ async def default_verify(self, synapse: "Synapse"):
976976
):
977977
raise Exception("Nonce is too old, a newer one was last processed")
978978

979-
if not keypair.verify(message, synapse.dendrite.signature):
979+
if synapse.dendrite.signature and not keypair.verify(
980+
message, synapse.dendrite.signature
981+
):
980982
raise Exception(
981983
f"Signature mismatch with {message} and {synapse.dendrite.signature}"
982984
)

bittensor/core/chain_data/utils.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Chain data helper functions and data."""
22

33
from enum import Enum
4-
from typing import Optional, Union
4+
from typing import Optional, Union, TYPE_CHECKING
55

66
from scalecodec.base import RuntimeConfiguration, ScaleBytes
77
from scalecodec.type_registry import load_type_registry_preset
@@ -10,6 +10,9 @@
1010
from bittensor.core.settings import SS58_FORMAT
1111
from bittensor.utils.balance import Balance
1212

13+
if TYPE_CHECKING:
14+
from async_substrate_interface.types import ScaleObj
15+
1316

1417
class ChainDataType(Enum):
1518
NeuronInfo = 1
@@ -135,3 +138,36 @@ def decode_metadata(metadata: dict) -> str:
135138
commitment = metadata["info"]["fields"][0][0]
136139
bytes_tuple = commitment[next(iter(commitment.keys()))][0]
137140
return bytes(bytes_tuple).decode()
141+
142+
143+
def decode_revealed_commitment(
144+
value: Optional["ScaleObj"],
145+
) -> Optional[tuple[int, str]]:
146+
"""Decode the revealed commitment data from the given input if it is not None."""
147+
if value is None:
148+
return None
149+
150+
def scale_decode_offset(data: bytes) -> int:
151+
"""Decodes the scale offset from a given byte data sequence."""
152+
first_byte = data[0]
153+
mode = first_byte & 0b11
154+
if mode == 0:
155+
return 1
156+
elif mode == 1:
157+
return 2
158+
else:
159+
return 4
160+
161+
v = next(iter(value))
162+
revealed_block = v[1]
163+
cut = scale_decode_offset(v[0])
164+
165+
revealed_commitment = bytes(v[0][cut:]).decode("utf-8", errors="ignore")
166+
return revealed_block, revealed_commitment
167+
168+
169+
def decode_revealed_commitment_with_hotkey(data: list) -> dict[str, tuple[int, str]]:
170+
"""Decode revealed commitment using a hotkey."""
171+
key, value = data
172+
ss58_address = decode_account_id(key[0])
173+
return {ss58_address: decode_revealed_commitment(value)}

bittensor/core/extrinsics/asyncex/serving.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import asyncio
2-
from typing import Optional, TYPE_CHECKING
2+
from typing import Optional, Union, TYPE_CHECKING
33

44
from bittensor.core.errors import MetadataError
55
from bittensor.core.settings import version_as_int
@@ -226,7 +226,7 @@ async def publish_metadata(
226226
wallet: "Wallet",
227227
netuid: int,
228228
data_type: str,
229-
data: bytes,
229+
data: Union[bytes, dict],
230230
wait_for_inclusion: bool = False,
231231
wait_for_finalization: bool = True,
232232
) -> bool:
@@ -240,8 +240,8 @@ async def publish_metadata(
240240
data_type (str): The data type of the information being submitted. It should be one of the following:
241241
``'Sha256'``, ``'Blake256'``, ``'Keccak256'``, or ``'Raw0-128'``. This specifies the format or hashing
242242
algorithm used for the data.
243-
data (str): The actual metadata content to be published. This should be formatted or hashed according to the
244-
``type`` specified. (Note: max ``str`` length is 128 bytes)
243+
data (Union[bytes, dict]): The actual metadata content to be published. This should be formatted or hashed
244+
according to the ``type`` specified. (Note: max ``str`` length is 128 bytes for ``'Raw0-128'``.)
245245
wait_for_inclusion (bool, optional): If ``True``, the function will wait for the extrinsic to be included in a
246246
block before returning. Defaults to ``False``.
247247
wait_for_finalization (bool, optional): If ``True``, the function will wait for the extrinsic to be finalized

bittensor/core/extrinsics/asyncex/weights.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ async def set_weights_extrinsic(
319319
)
320320

321321
logging.info(
322-
":satellite: [magenta]Setting weights on [/magenta][blue]{subtensor.network}[/blue] [magenta]...[/magenta]"
322+
f":satellite: [magenta]Setting weights on [/magenta][blue]{subtensor.network}[/blue] [magenta]...[/magenta]"
323323
)
324324
try:
325325
success, error_message = await _do_set_weights(

bittensor/core/extrinsics/serving.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional, TYPE_CHECKING
1+
from typing import Optional, Union, TYPE_CHECKING
22

33
from bittensor.core.errors import MetadataError
44
from bittensor.core.settings import version_as_int
@@ -222,7 +222,7 @@ def publish_metadata(
222222
wallet: "Wallet",
223223
netuid: int,
224224
data_type: str,
225-
data: bytes,
225+
data: Union[bytes, dict],
226226
wait_for_inclusion: bool = False,
227227
wait_for_finalization: bool = True,
228228
) -> bool:
@@ -236,8 +236,8 @@ def publish_metadata(
236236
data_type (str): The data type of the information being submitted. It should be one of the following:
237237
``'Sha256'``, ``'Blake256'``, ``'Keccak256'``, or ``'Raw0-128'``. This specifies the format or hashing
238238
algorithm used for the data.
239-
data (str): The actual metadata content to be published. This should be formatted or hashed according to the
240-
``type`` specified. (Note: max ``str`` length is 128 bytes)
239+
data (Union[bytes, dict]): The actual metadata content to be published. This should be formatted or hashed
240+
according to the ``type`` specified. (Note: max ``str`` length is 128 bytes for ``'Raw0-128'``.)
241241
wait_for_inclusion (bool, optional): If ``True``, the function will wait for the extrinsic to be included in a
242242
block before returning. Defaults to ``False``.
243243
wait_for_finalization (bool, optional): If ``True``, the function will wait for the extrinsic to be finalized

bittensor/core/extrinsics/set_weights.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def set_weights_extrinsic(
123123
)
124124

125125
logging.info(
126-
":satellite: [magenta]Setting weights on [/magenta][blue]{subtensor.network}[/blue] [magenta]...[/magenta]"
126+
f":satellite: [magenta]Setting weights on [/magenta][blue]{subtensor.network}[/blue] [magenta]...[/magenta]"
127127
)
128128
try:
129129
success, error_message = _do_set_weights(

0 commit comments

Comments
 (0)