Skip to content
This repository was archived by the owner on Jul 10, 2026. It is now read-only.

Commit 360d46c

Browse files
Merge branch 'staging' into edit-docstrings-async-subtensor-part2
2 parents 828343e + 0adcd7b commit 360d46c

51 files changed

Lines changed: 1466 additions & 509 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e-subtensor-tests.yaml

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,37 @@ jobs:
3333
- name: Check-out repository under $GITHUB_WORKSPACE
3434
uses: actions/checkout@v4
3535

36+
- name: Set up Python
37+
uses: actions/setup-python@v5
38+
with:
39+
python-version: '3.11'
40+
41+
- name: Install deps for collection
42+
run: |
43+
python -m pip install --upgrade pip
44+
pip install -e ".[dev]"
45+
3646
- name: Find test files
3747
id: get-tests
38-
run: |
39-
test_files=$(find tests/e2e_tests -name "test*.py" | jq -R -s -c 'split("\n") | map(select(. != ""))')
40-
# keep it here for future debug
41-
# test_files=$(find tests/e2e_tests -type f -name "test*.py" | grep -E 'test_(hotkeys|staking)\.py$' | jq -R -s -c 'split("\n") | map(select(. != ""))')
42-
echo "Found test files: $test_files"
43-
echo "test-files=$test_files" >> "$GITHUB_OUTPUT"
4448
shell: bash
49+
run: |
50+
set -euo pipefail
51+
test_matrix=$(
52+
pytest -q --collect-only tests/e2e_tests \
53+
| sed -n '/^e2e_tests\//p' \
54+
| sed 's|^|tests/|' \
55+
| jq -R -s -c '
56+
split("\n")
57+
| map(select(. != ""))
58+
| map({nodeid: ., label: (sub("^tests/e2e_tests/"; ""))})
59+
'
60+
)
61+
echo "Found tests: $test_matrix"
62+
echo "test-files=$test_matrix" >> "$GITHUB_OUTPUT"
4563
4664
# Pull docker image
4765
pull-docker-image:
66+
needs: find-tests
4867
runs-on: ubuntu-latest
4968
outputs:
5069
image-name: ${{ steps.set-image.outputs.image }}
@@ -111,19 +130,19 @@ jobs:
111130

112131
# Job to run tests in parallel
113132
run-fast-blocks-e2e-test:
114-
name: "FB: ${{ matrix.test-file }} / Python ${{ matrix.python-version }}"
133+
name: "${{ matrix.test.label }} / Py ${{ matrix.python-version }}"
115134
needs:
116135
- find-tests
117136
- pull-docker-image
118137
runs-on: ubuntu-latest
119138
timeout-minutes: 45
120139
strategy:
121140
fail-fast: false # Allow other matrix jobs to run even if this job fails
122-
max-parallel: 32 # Set the maximum number of parallel jobs (same as we have cores in ubuntu-latest runner)
141+
max-parallel: 64 # Set the maximum number of parallel jobs (same as we have cores in ubuntu-latest runner)
123142
matrix:
124143
os:
125144
- ubuntu-latest
126-
test-file: ${{ fromJson(needs.find-tests.outputs.test-files) }}
145+
test: ${{ fromJson(needs.find-tests.outputs.test-files) }}
127146
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
128147
steps:
129148
- name: Check-out repository
@@ -154,7 +173,7 @@ jobs:
154173
run: |
155174
for i in 1 2 3; do
156175
echo "::group::🔁 Test attempt $i"
157-
if uv run pytest ${{ matrix.test-file }} -s; then
176+
if uv run pytest "${{ matrix.test.nodeid }}" -s; then
158177
echo "✅ Tests passed on attempt $i"
159178
echo "::endgroup::"
160179
exit 0

.github/workflows/flake8-and-mypy.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ jobs:
4242
python -m venv venv
4343
source venv/bin/activate
4444
python -m pip install --upgrade pip
45-
python -m pip install uv
45+
# needed for Python 3.9 compatibility
46+
python -m pip install uv>=0.8.8
4647
python -m uv sync --extra dev --active
4748
4849
- name: Flake8

.github/workflows/unit-and-integration-tests.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ jobs:
3939
python -m venv venv
4040
source venv/bin/activate
4141
python -m pip install --upgrade pip
42-
python -m pip install uv
42+
# needed for Python 3.9 compatibility
43+
python -m pip install uv>=0.8.8
4344
python -m uv sync --extra dev --active
4445
4546
- name: Unit tests

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
# Changelog
22

3+
## 9.9.0 /2025-08-11
4+
5+
## What's Changed
6+
* Fix crv3 tests after devnet-ready get `CRV3WeightCommitsV2` by @basfroman in https://github.com/opentensor/bittensor/pull/2978
7+
* Add webhook for failed nightly tests by @basfroman in https://github.com/opentensor/bittensor/pull/2987
8+
* Fix liquidity test (non-fast-blocks node) by @basfroman in https://github.com/opentensor/bittensor/pull/2988
9+
* improve nightly logic by @basfroman in https://github.com/opentensor/bittensor/pull/2989
10+
* improve nightly 2 by @basfroman in https://github.com/opentensor/bittensor/pull/2990
11+
* Add `get_stake_weight` methods by @basfroman in https://github.com/opentensor/bittensor/pull/2985
12+
* Handles both exceptions for Swap pallet fetching by @thewhaleking in https://github.com/opentensor/bittensor/pull/2991
13+
* chore: fix typo by @socialsister in https://github.com/opentensor/bittensor/pull/2969
14+
* optimisations mostly related to liquidity_list by @thewhaleking in https://github.com/opentensor/bittensor/pull/2980
15+
* Transfers improvements by @thewhaleking in https://github.com/opentensor/bittensor/pull/2993
16+
* Remove ownership check in `transfer_stake_extrinsic` and `swap_stake_extrinsic` by @basfroman in https://github.com/opentensor/bittensor/pull/2996
17+
* Missed await by @thewhaleking in https://github.com/opentensor/bittensor/pull/3002
18+
* chore: fix typo by @lechpzn in https://github.com/opentensor/bittensor/pull/3001
19+
* Adds note for installing on macOS by @thewhaleking in https://github.com/opentensor/bittensor/pull/3004
20+
* Bump bittensor-wallet version by @thewhaleking in https://github.com/opentensor/bittensor/pull/3005
21+
* Format Error with string docs by @thewhaleking in https://github.com/opentensor/bittensor/pull/3006
22+
* `LoggingMachine` initialization updated to explicitly call both parent constructors by @basfroman in https://github.com/opentensor/bittensor/pull/3008
23+
* Fixed `moving_price` conversion from `I96F32` to float by @mcjkula in https://github.com/opentensor/bittensor/pull/3010
24+
* Add new CRv4 logic by @basfroman in https://github.com/opentensor/bittensor/pull/2999
25+
* UV Fix by @thewhaleking in https://github.com/opentensor/bittensor/pull/3011
26+
27+
## New Contributors
28+
* @socialsister made their first contribution in https://github.com/opentensor/bittensor/pull/2969
29+
* @lechpzn made their first contribution in https://github.com/opentensor/bittensor/pull/3001
30+
* @mcjkula made their first contribution in https://github.com/opentensor/bittensor/pull/3010
31+
32+
**Full Changelog**: https://github.com/opentensor/bittensor/compare/v9.8.3...v9.9.0
33+
334
## 9.8.3 /2025-07-18
435
* improve make file by @basfroman in https://github.com/opentensor/bittensor/pull/2965
536
* Move all workflows from `app.circleci.com` to `GH actions` by @basfroman in https://github.com/opentensor/bittensor/pull/2970

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ python3 -m pip install --upgrade bittensor
9494

9595
## Install on macOS and Linux
9696

97+
### Note for macOS users
98+
The macOS preinstalled CPython installation is compiled with LibreSSL instead of OpenSSL. There are a number
99+
of issues with LibreSSL, and as such is not fully supported by the libraries used by bittensor. Thus we highly recommend, if
100+
you are using a Mac, to first install Python from [Homebrew](https://brew.sh/). Additionally, the Rust FFI bindings
101+
[if installing from precompiled wheels (default)] require the Homebrew-installed OpenSSL pacakge. If you choose to use
102+
the preinstalled Python version from macOS, things may not work completely.
103+
104+
### Installation
97105
You can install Bittensor SDK on your local machine in either of the following ways. **Make sure you verify your installation after you install**:
98106
- [Install using a Bash command](#install-using-a-bash-command).
99107
- [Install using `pip3 install`](#install-using-pip3-install)
@@ -158,6 +166,13 @@ You can install using any of the below options:
158166
1. Install `cubit` first. See the [Install](https://github.com/opentensor/cubit?tab=readme-ov-file#install) section. **Only Python 3.9 and 3.10 versions are supported**.
159167
2. Then install SDK with `pip install bittensor`.
160168

169+
170+
### Troubleshooting
171+
#### SSL: CERTIFICATE_VERIFY_FAILED
172+
173+
If you are encountering a `[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate`
174+
error, use the command `python -m bittensor certifi` which will update your local SSL certificates.
175+
161176
---
162177

163178
## Install on Windows

bittensor/core/async_subtensor.py

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
torch,
9999
u16_normalized_float,
100100
u64_normalized_float,
101+
get_transfer_fn_params,
101102
)
102103
from bittensor.core.extrinsics.asyncex.liquidity import (
103104
add_liquidity_extrinsic,
@@ -2112,7 +2113,7 @@ async def get_delegated(
21122113
block: Optional[int] = None,
21132114
block_hash: Optional[str] = None,
21142115
reuse_block: bool = False,
2115-
) -> list[tuple[DelegateInfo, Balance]]:
2116+
) -> list[DelegatedInfo]:
21162117
"""
21172118
Retrieves a list of delegates and their associated stakes for a given coldkey. This function identifies the
21182119
delegates that a specific account has staked tokens on.
@@ -2124,7 +2125,7 @@ async def get_delegated(
21242125
reuse_block: Whether to reuse the last-used blockchain block hash.
21252126
21262127
Returns:
2127-
A list of tuples, each containing a delegate's information and staked amount.
2128+
A list containing the delegated information for the specified coldkey.
21282129
21292130
This function is important for account holders to understand their stake allocations and their involvement in
21302131
the network's delegation and consensus mechanisms.
@@ -2808,6 +2809,7 @@ async def get_next_epoch_start_block(
28082809
netuid=netuid, block=block, block_hash=block_hash, reuse_block=reuse_block
28092810
)
28102811

2812+
block = block or await self.substrate.get_block_number(block_hash=block_hash)
28112813
if block and blocks_since_last_step is not None and tempo:
28122814
return block - blocks_since_last_step + tempo + 1
28132815
return None
@@ -3055,6 +3057,45 @@ async def get_subnet_prices(
30553057
prices.update({0: Balance.from_tao(1)})
30563058
return prices
30573059

3060+
async def get_timelocked_weight_commits(
3061+
self,
3062+
netuid: int,
3063+
block: Optional[int] = None,
3064+
block_hash: Optional[str] = None,
3065+
reuse_block: bool = False,
3066+
) -> list[tuple[str, int, str, int]]:
3067+
"""
3068+
Retrieves CRv4 weight commit information for a specific subnet.
3069+
3070+
Arguments:
3071+
netuid (int): The unique identifier of the subnet.
3072+
block (Optional[int]): The blockchain block number for the query. Default is ``None``.
3073+
block_hash: The hash of the block to retrieve the stake from. Do not specify if using block
3074+
or reuse_block
3075+
reuse_block: Whether to use the last-used block. Do not set if using block_hash or block.
3076+
3077+
Returns:
3078+
A list of commit details, where each item contains:
3079+
- ss58_address: The address of the committer.
3080+
- commit_block: The block number when the commitment was made.
3081+
- commit_message: The commit message.
3082+
- reveal_round: The round when the commitment was revealed.
3083+
3084+
The list may be empty if there are no commits found.
3085+
"""
3086+
block_hash = await self.determine_block_hash(
3087+
block=block, block_hash=block_hash, reuse_block=reuse_block
3088+
)
3089+
result = await self.substrate.query_map(
3090+
module="SubtensorModule",
3091+
storage_function="TimelockedWeightCommits",
3092+
params=[netuid],
3093+
block_hash=block_hash,
3094+
)
3095+
3096+
commits = result.records[0][1] if result.records else []
3097+
return [WeightCommitInfo.from_vec_u8_v2(commit) for commit in commits]
3098+
30583099
# TODO: remove unused parameters in SDK.v10
30593100
async def get_unstake_fee(
30603101
self,
@@ -3559,7 +3600,7 @@ async def get_total_subnets(
35593600
return getattr(result, "value", None)
35603601

35613602
async def get_transfer_fee(
3562-
self, wallet: "Wallet", dest: str, value: Balance
3603+
self, wallet: "Wallet", dest: str, value: Balance, keep_alive: bool = True
35633604
) -> Balance:
35643605
"""
35653606
Calculates the transaction fee for transferring tokens from a wallet to a specified destination address. This
@@ -3571,6 +3612,8 @@ async def get_transfer_fee(
35713612
dest: The SS58 address of the destination account.
35723613
value: The amount of tokens to be transferred, specified as a Balance object, or in Tao (float) or Rao
35733614
(int) units.
3615+
keep_alive: Whether the transfer fee should be calculated based on keeping the wallet alive (existential
3616+
deposit) or not.
35743617
35753618
Returns:
35763619
bittensor.utils.balance.Balance: The estimated transaction fee for the transfer, represented as a Balance
@@ -3588,12 +3631,15 @@ async def get_transfer_fee(
35883631
# TODO: Add guidance on handling fee estimation failures
35893632
# TODO: Show how to budget for transfers including fees
35903633
"""
3591-
value = check_and_convert_to_balance(value)
3634+
if value is not None:
3635+
value = check_and_convert_to_balance(value)
3636+
call_params: dict[str, Union[int, str, bool]]
3637+
call_function, call_params = get_transfer_fn_params(value, dest, keep_alive)
35923638

35933639
call = await self.substrate.compose_call(
35943640
call_module="Balances",
3595-
call_function="transfer_keep_alive",
3596-
call_params={"dest": dest, "value": value.rao},
3641+
call_function=call_function,
3642+
call_params=call_params,
35973643
)
35983644

35993645
try:
@@ -5262,10 +5308,11 @@ async def move_stake(
52625308
origin_netuid: int,
52635309
destination_hotkey: str,
52645310
destination_netuid: int,
5265-
amount: Balance,
5311+
amount: Optional[Balance] = None,
52665312
wait_for_inclusion: bool = True,
52675313
wait_for_finalization: bool = False,
52685314
period: Optional[int] = None,
5315+
move_all_stake: bool = False,
52695316
) -> bool:
52705317
"""
52715318
Moves stake to a different hotkey and/or subnet.
@@ -5282,6 +5329,7 @@ async def move_stake(
52825329
period: The number of blocks during which the transaction will remain valid after it's
52835330
submitted. If the transaction is not included in a block within that number of blocks, it will expire
52845331
and be rejected. You can think of it as an expiration date for the transaction.
5332+
move_all_stake: If true, moves all stake from the source hotkey to the destination hotkey.
52855333
52865334
Returns:
52875335
success: True if the stake movement was successful.
@@ -5298,6 +5346,7 @@ async def move_stake(
52985346
wait_for_inclusion=wait_for_inclusion,
52995347
wait_for_finalization=wait_for_finalization,
53005348
period=period,
5349+
move_all_stake=move_all_stake,
53015350
)
53025351

53035352
async def register(
@@ -6107,7 +6156,7 @@ async def transfer(
61076156
self,
61086157
wallet: "Wallet",
61096158
dest: str,
6110-
amount: Balance,
6159+
amount: Optional[Balance],
61116160
transfer_all: bool = False,
61126161
wait_for_inclusion: bool = True,
61136162
wait_for_finalization: bool = False,
@@ -6120,18 +6169,19 @@ async def transfer(
61206169
Arguments:
61216170
wallet: Source wallet for the transfer.
61226171
dest: Destination address for the transfer.
6123-
amount: Number of tokens to transfer.
6124-
transfer_all: Flag to transfer all tokens. Default is ``False``.
6125-
wait_for_inclusion: Waits for the transaction to be included in a block. Defaults to ``True``.
6126-
wait_for_finalization: Waits for the transaction to be finalized on the blockchain. Defaults to ``False``.
6127-
keep_alive: Flag to keep the connection alive. Default is ``True``.
6172+
amount: Number of tokens to transfer. `None` is transferring all.
6173+
transfer_all: Flag to transfer all tokens. Default is `False`.
6174+
wait_for_inclusion: Waits for the transaction to be included in a block. Defaults to `True`.
6175+
wait_for_finalization: Waits for the transaction to be finalized on the blockchain. Defaults to `False`.
6176+
keep_alive: Flag to keep the connection alive. Default is `True`.
61286177
period: The number of blocks during which the transaction will remain valid after it's submitted. If the
61296178
transaction is not included in a block within that number of blocks, it will expire and be rejected. You
61306179
can think of it as an expiration date for the transaction.
61316180
Returns:
61326181
``True`` if the transferring was successful, otherwise ``False``.
61336182
"""
6134-
amount = check_and_convert_to_balance(amount)
6183+
if amount is not None:
6184+
amount = check_and_convert_to_balance(amount)
61356185
return await transfer_extrinsic(
61366186
subtensor=self,
61376187
wallet=wallet,
@@ -6193,7 +6243,7 @@ async def unstake(
61936243
self,
61946244
wallet: "Wallet",
61956245
hotkey_ss58: Optional[str] = None,
6196-
netuid: Optional[int] = None,
6246+
netuid: Optional[int] = None, # TODO why is this optional?
61976247
amount: Optional[Balance] = None,
61986248
wait_for_inclusion: bool = True,
61996249
wait_for_finalization: bool = False,

bittensor/core/chain_data/dynamic_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def _from_dict(cls, decoded: dict) -> "DynamicInfo":
126126
network_registered_at=int(decoded["network_registered_at"]),
127127
subnet_identity=subnet_identity,
128128
subnet_volume=subnet_volume,
129-
moving_price=fixed_to_float(decoded["moving_price"]),
129+
moving_price=fixed_to_float(decoded["moving_price"], 32),
130130
)
131131

132132
def tao_to_alpha(self, tao: Union[Balance, float, int]) -> Balance:

0 commit comments

Comments
 (0)