Skip to content

Commit 9b6d63e

Browse files
authored
Merge branch 'staging' into patch-2
2 parents b09aec0 + a70bee8 commit 9b6d63e

File tree

5 files changed

+84
-5
lines changed

5 files changed

+84
-5
lines changed

bittensor/core/async_subtensor.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,38 @@ async def get_neuron_for_pubkey_and_subnet(
16871687
reuse_block=reuse_block,
16881688
)
16891689

1690+
async def get_next_epoch_start_block(
1691+
self,
1692+
netuid: int,
1693+
block: Optional[int] = None,
1694+
block_hash: Optional[str] = None,
1695+
reuse_block: bool = False,
1696+
) -> Optional[int]:
1697+
"""
1698+
Calculates the first block number of the next epoch for the given subnet.
1699+
1700+
If `block` is not provided, the current chain block will be used. Epochs are
1701+
determined based on the subnet's tempo (i.e., blocks per epoch). The result
1702+
is the block number at which the next epoch will begin.
1703+
1704+
Args:
1705+
netuid (int): The unique identifier of the subnet.
1706+
block (Optional[int], optional): The reference block to calculate from.
1707+
If None, uses the current chain block height.
1708+
block_hash (Optional[int]): The blockchain block number at which to perform the query.
1709+
reuse_block (bool): Whether to reuse the last-used blockchain block hash.
1710+
1711+
1712+
Returns:
1713+
int: The block number at which the next epoch will start.
1714+
"""
1715+
block_hash = await self.determine_block_hash(block, block_hash, reuse_block)
1716+
if not block_hash and reuse_block:
1717+
block_hash = self.substrate.last_block_hash
1718+
block = await self.substrate.get_block_number(block_hash=block_hash)
1719+
tempo = await self.tempo(netuid=netuid, block_hash=block_hash)
1720+
return (((block // tempo) + 1) * tempo) + 1 if tempo else None
1721+
16901722
async def get_owned_hotkeys(
16911723
self,
16921724
coldkey_ss58: str,

bittensor/core/metagraph.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import contextlib
23
import copy
34
import os
45
import pickle
@@ -11,6 +12,7 @@
1112
import numpy as np
1213
from async_substrate_interface.errors import SubstrateRequestException
1314
from numpy.typing import NDArray
15+
from packaging import version
1416

1517
from bittensor.core import settings
1618
from bittensor.core.chain_data import (
@@ -143,6 +145,27 @@ def latest_block_path(dir_path: str) -> str:
143145
return latest_file_full_path
144146

145147

148+
def safe_globals():
149+
"""
150+
Context manager to load torch files for version 2.6+
151+
"""
152+
if version.parse(torch.__version__).release < version.parse("2.6").release:
153+
return contextlib.nullcontext()
154+
155+
np_core = (
156+
np._core if version.parse(np.__version__) >= version.parse("2.0.0") else np.core
157+
)
158+
allow_list = [
159+
np_core.multiarray._reconstruct,
160+
np.ndarray,
161+
np.dtype,
162+
type(np.dtype(np.uint32)),
163+
np.dtypes.Float32DType,
164+
bytes,
165+
]
166+
return torch.serialization.safe_globals(allow_list)
167+
168+
146169
class MetagraphMixin(ABC):
147170
"""
148171
The metagraph class is a core component of the Bittensor network, representing the neural graph that forms the
@@ -1124,7 +1147,8 @@ def load_from_path(self, dir_path: str) -> "MetagraphMixin":
11241147
"""
11251148

11261149
graph_file = latest_block_path(dir_path)
1127-
state_dict = torch.load(graph_file)
1150+
with safe_globals():
1151+
state_dict = torch.load(graph_file)
11281152
self.n = torch.nn.Parameter(state_dict["n"], requires_grad=False)
11291153
self.block = torch.nn.Parameter(state_dict["block"], requires_grad=False)
11301154
self.uids = torch.nn.Parameter(state_dict["uids"], requires_grad=False)
@@ -1256,7 +1280,8 @@ def load_from_path(self, dir_path: str) -> "MetagraphMixin":
12561280
try:
12571281
import torch as real_torch
12581282

1259-
state_dict = real_torch.load(graph_filename)
1283+
with safe_globals():
1284+
state_dict = real_torch.load(graph_filename)
12601285
for key in METAGRAPH_STATE_DICT_NDARRAY_KEYS:
12611286
state_dict[key] = state_dict[key].detach().numpy()
12621287
del real_torch

bittensor/core/subtensor.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,28 @@ def get_neuron_for_pubkey_and_subnet(
13001300

13011301
return NeuronInfo.from_dict(result)
13021302

1303+
def get_next_epoch_start_block(
1304+
self, netuid: int, block: Optional[int] = None
1305+
) -> Optional[int]:
1306+
"""
1307+
Calculates the first block number of the next epoch for the given subnet.
1308+
1309+
If `block` is not provided, the current chain block will be used. Epochs are
1310+
determined based on the subnet's tempo (i.e., blocks per epoch). The result
1311+
is the block number at which the next epoch will begin.
1312+
1313+
Args:
1314+
netuid (int): The unique identifier of the subnet.
1315+
block (Optional[int], optional): The reference block to calculate from.
1316+
If None, uses the current chain block height.
1317+
1318+
Returns:
1319+
int: The block number at which the next epoch will start.
1320+
"""
1321+
block = block or self.block
1322+
tempo = self.tempo(netuid=netuid, block=block)
1323+
return (((block // tempo) + 1) * tempo) + 1 if tempo else None
1324+
13031325
def get_owned_hotkeys(
13041326
self,
13051327
coldkey_ss58: str,

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ dev = [
5959
"aioresponses==0.7.6",
6060
"factory-boy==3.3.0",
6161
"types-requests",
62-
"torch>=1.13.1,<2.6.0"
62+
"torch>=1.13.1,<3.0"
6363
]
6464
torch = [
65-
"torch>=1.13.1,<2.6.0"
65+
"torch>=1.13.1,<3.0"
6666
]
6767
cli = [
6868
"bittensor-cli>=9.0.2"

requirements/torch.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
torch>=1.13.1,<2.6.0
1+
torch>=1.13.1,<3.0

0 commit comments

Comments
 (0)