Skip to content

Commit 61c8c70

Browse files
authored
Merge branch 'staging' into fix/zyzniewski/async_get_delegated
2 parents 19de20b + a88e2d7 commit 61c8c70

File tree

5 files changed

+91
-0
lines changed

5 files changed

+91
-0
lines changed

bittensor/core/async_subtensor.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import copy
3+
from datetime import datetime, timezone
34
import ssl
45
from functools import partial
56
from typing import Optional, Any, Union, Iterable, TYPE_CHECKING
@@ -2745,6 +2746,36 @@ async def weights_rate_limit(
27452746
)
27462747
return None if call is None else int(call)
27472748

2749+
async def get_timestamp(
2750+
self,
2751+
block: Optional[int] = None,
2752+
block_hash: Optional[str] = None,
2753+
reuse_block: bool = False,
2754+
) -> datetime:
2755+
"""
2756+
Retrieves the datetime timestamp for a given block
2757+
2758+
Arguments:
2759+
block: The blockchain block number for the query. Do not specify if specifying block_hash or reuse_block.
2760+
block_hash: The blockchain block_hash representation of the block id. Do not specify if specifying block
2761+
or reuse_block.
2762+
reuse_block: Whether to reuse the last-used blockchain block hash. Do not specify if specifying block or
2763+
block_hash.
2764+
2765+
Returns:
2766+
datetime object for the timestamp of the block
2767+
"""
2768+
unix = (
2769+
await self.query_module(
2770+
"Timestamp",
2771+
"Now",
2772+
block=block,
2773+
block_hash=block_hash,
2774+
reuse_block=reuse_block,
2775+
)
2776+
).value
2777+
return datetime.fromtimestamp(unix / 1000, tz=timezone.utc)
2778+
27482779
# Extrinsics helper ================================================================================================
27492780

27502781
async def sign_and_send_extrinsic(

bittensor/core/subtensor.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import copy
2+
from datetime import datetime, timezone
3+
24
from functools import lru_cache
35
from typing import TYPE_CHECKING, Any, Iterable, Optional, Union, cast
46

@@ -2070,6 +2072,19 @@ def weights_rate_limit(
20702072
)
20712073
return None if call is None else int(call)
20722074

2075+
def get_timestamp(self, block: Optional[int] = None) -> datetime:
2076+
"""
2077+
Retrieves the datetime timestamp for a given block
2078+
2079+
Arguments:
2080+
block: The blockchain block number for the query.
2081+
2082+
Returns:
2083+
datetime object for the timestamp of the block
2084+
"""
2085+
unix = cast(ScaleObj, self.query_module("Timestamp", "Now", block=block)).value
2086+
return datetime.fromtimestamp(unix / 1000, tz=timezone.utc)
2087+
20732088
# Extrinsics helper ================================================================================================
20742089

20752090
def sign_and_send_extrinsic(
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from datetime import datetime
2+
import pytest
3+
4+
5+
@pytest.mark.asyncio
6+
async def test_get_timestamp(subtensor, async_subtensor, local_chain):
7+
with subtensor:
8+
block_number = subtensor.get_current_block()
9+
assert isinstance(
10+
subtensor.get_timestamp(), datetime
11+
) # verify it works with no block number specified
12+
sync_result = subtensor.get_timestamp(
13+
block=block_number
14+
) # verify it works with block number specified
15+
async with async_subtensor:
16+
assert isinstance(await async_subtensor.get_timestamp(), datetime)
17+
async_result = await async_subtensor.get_timestamp(block=block_number)
18+
assert sync_result == async_result

tests/unit_tests/test_async_subtensor.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import datetime
12
import unittest.mock as mock
23

34
import pytest
5+
from async_substrate_interface.types import ScaleObj
46
from bittensor_wallet import Wallet
57

68
from bittensor import u64_normalized_float
@@ -2690,3 +2692,15 @@ async def test_get_all_neuron_certificates(mocker, subtensor):
26902692
block_hash=None,
26912693
reuse_block_hash=False,
26922694
)
2695+
2696+
2697+
@pytest.mark.asyncio
2698+
async def test_get_timestamp(mocker, subtensor):
2699+
fake_block = 1000
2700+
mocked_query = mocker.AsyncMock(return_value=ScaleObj(1740586018 * 1000))
2701+
mocker.patch.object(subtensor.substrate, "query", mocked_query)
2702+
expected_result = datetime.datetime(
2703+
2025, 2, 26, 16, 6, 58, tzinfo=datetime.timezone.utc
2704+
)
2705+
actual_result = await subtensor.get_timestamp(block=fake_block)
2706+
assert expected_result == actual_result

tests/unit_tests/test_subtensor.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717

1818
import argparse
1919
import unittest.mock as mock
20+
import datetime
2021
from unittest.mock import MagicMock
2122

2223
import pytest
2324
from bittensor_wallet import Wallet
2425
from async_substrate_interface import sync_substrate
26+
from async_substrate_interface.types import ScaleObj
2527
import websockets
2628

2729
from bittensor import StakeInfo
@@ -3073,3 +3075,14 @@ def test_get_all_neuron_certificates(mocker, subtensor):
30733075
params=[fake_netuid],
30743076
block_hash=None,
30753077
)
3078+
3079+
3080+
def test_get_timestamp(mocker, subtensor):
3081+
fake_block = 1000
3082+
mocked_query = mocker.MagicMock(return_value=ScaleObj(1740586018 * 1000))
3083+
mocker.patch.object(subtensor.substrate, "query", mocked_query)
3084+
expected_result = datetime.datetime(
3085+
2025, 2, 26, 16, 6, 58, tzinfo=datetime.timezone.utc
3086+
)
3087+
actual_result = subtensor.get_timestamp(block=fake_block)
3088+
assert expected_result == actual_result

0 commit comments

Comments
 (0)