Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ac81421
fix: reflect correct return types for get_delegated
Arthurdw Aug 14, 2025
ad9aa79
fix: it is actually delegated info not delegate info
Arthurdw Aug 14, 2025
3edcbb4
Added fee calculation and fixed tests for burned register.
thewhaleking Aug 15, 2025
46d7847
Added fee calculation for unstaking. Added TODOs with questions.
thewhaleking Aug 15, 2025
a7b76b5
Added fee calculation for sync unstaking aswell
thewhaleking Aug 15, 2025
3991115
Ruff
thewhaleking Aug 15, 2025
d610bf5
Fix unit tests
thewhaleking Aug 15, 2025
feecd2b
fix `test_commit_and_reveal_weights_cr4` (included non-fast-runtime)
Aug 19, 2025
5df01b6
move `get_unstaking_fee` to `utils.py` modules. update extrinsics
Aug 19, 2025
737aa3e
improve `get_unstaking_fee`
Aug 20, 2025
ef3f95a
improve `unstaking` extrinsics logging
Aug 20, 2025
ac0f9c5
improve `_do_burned_register` extrinsics calls
Aug 20, 2025
7c1c543
opps, fix async `get_extrinsic_fee`
Aug 20, 2025
101d716
try to fix `tests/e2e_tests/test_liquidity.py`
Aug 20, 2025
f670b1d
fix comment
Aug 20, 2025
bfe5a0e
use `CLOSE_IN_VALUE` in `test_batch_operations`
Aug 20, 2025
b855e8e
Merge pull request #3020 from opentensor/fix/thewhaleking/broken-e2e-…
basfroman Aug 20, 2025
9a59981
fix bug in `bittensor.core.async_subtensor.AsyncSubtensor.get_next_ep…
Aug 21, 2025
9605028
add `tests.e2e_tests.utils.chain_interactions.async_wait_interval` fo…
Aug 21, 2025
a143cff
add `tests.e2e_tests.test_commit_reveal.test_async_commit_and_reveal_…
Aug 21, 2025
68c4eaa
Merge pull request #3022 from opentensor/feat/roman/add-async-test-crv4
basfroman Aug 21, 2025
95d6f68
add `get_timelocked_weight_commits` method
Aug 21, 2025
30fdd80
update SubtensorApi
Aug 21, 2025
b7a5e40
add unit tests
Aug 21, 2025
f4603a5
update e2e test
Aug 21, 2025
ac80745
merge: branch 'staging' into PATCH-reflect-correct-types-for-get_dele…
Arthurdw Aug 22, 2025
2e903fc
Merge pull request #3023 from opentensor/feat/roman/use-TimelockedWei…
basfroman Aug 22, 2025
c50bea7
increase tempo, readability
Aug 23, 2025
688eba2
merge: branch 'staging' into PATCH-reflect-correct-types-for-get_dele…
Arthurdw Aug 24, 2025
daeb3e2
Merge pull request #3016 from Arthurdw/PATCH-reflect-correct-types-fo…
thewhaleking Aug 24, 2025
36209ea
Merge pull request #3025 from opentensor/fix/roman/fix-flaky-behavior…
basfroman Aug 25, 2025
bf979e8
fix `test_incentive`
Aug 25, 2025
7ab832f
fix `test_metagraph`
Aug 25, 2025
1505949
split test cases to each matrix item
Aug 25, 2025
74bc8a2
quote matrix test-file in pytest command
Aug 25, 2025
baf6239
try apply labels and increase `max-parallel`
Aug 25, 2025
21efc5b
include -> test + refer
Aug 25, 2025
fc93bbc
make test name shorter
Aug 25, 2025
9aa4b45
Use CamelCase in the name `CLOSE_IN_VALUE`
Aug 26, 2025
2b1789e
add `move_all_stake` parameter to `move_stake_extrinsic` extrinsic
Aug 26, 2025
c4c93d5
update `move_stake` methods in Subtensor class
Aug 26, 2025
f452699
update SubtensorApi
Aug 26, 2025
e1826b2
update helper
Aug 26, 2025
9a3cf94
refactoring
Aug 26, 2025
c9415a5
extend e2e test to check `move_stake` method behavior with `move_all_…
Aug 26, 2025
d5d6a55
Merge pull request #3027 from opentensor/test/roman/keep-each-file-as…
basfroman Aug 26, 2025
35bddb4
Merge branch 'staging' into feat/roman/Move-All-Stake-option
Aug 26, 2025
0adcd7b
Merge pull request #3028 from opentensor/feat/roman/Move-All-Stake-op…
basfroman Aug 26, 2025
2c5e221
Merge branch 'staging' into fix/roman/fix-tests-related-with-commit-r…
Aug 26, 2025
486dd78
Merge pull request #3026 from opentensor/fix/roman/fix-tests-related-…
basfroman Aug 26, 2025
1d10850
improve deps and version
Aug 28, 2025
c47fa43
CHANGELOG.md
Aug 28, 2025
fea35b0
Merge pull request #3031 from opentensor/changelog/9.10.0
basfroman Aug 28, 2025
d9c6e16
`actions/checkout@v4` should take all commits history
Aug 28, 2025
42d593d
Checkout PR head instead of merge
Aug 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions .github/workflows/e2e-subtensor-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,141 +32,166 @@
steps:
- name: Check-out repository under $GITHUB_WORKSPACE
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install deps for collection
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Find test files
id: get-tests
run: |
test_files=$(find tests/e2e_tests -name "test*.py" | jq -R -s -c 'split("\n") | map(select(. != ""))')
# keep it here for future debug
# 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(. != ""))')
echo "Found test files: $test_files"
echo "test-files=$test_files" >> "$GITHUB_OUTPUT"
shell: bash
run: |
set -euo pipefail
test_matrix=$(
pytest -q --collect-only tests/e2e_tests \
| sed -n '/^e2e_tests\//p' \
| sed 's|^|tests/|' \
| jq -R -s -c '
split("\n")
| map(select(. != ""))
| map({nodeid: ., label: (sub("^tests/e2e_tests/"; ""))})
'
)
echo "Found tests: $test_matrix"
echo "test-files=$test_matrix" >> "$GITHUB_OUTPUT"

# Pull docker image
pull-docker-image:
needs: find-tests
runs-on: ubuntu-latest
outputs:
image-name: ${{ steps.set-image.outputs.image }}
steps:
- name: Set Docker image tag based on label or branch
id: set-image
run: |
echo "Event: $GITHUB_EVENT_NAME"
echo "Branch: $GITHUB_REF_NAME"

echo "Reading labels ..."
if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then
labels=$(jq -r '.pull_request.labels[].name' "$GITHUB_EVENT_PATH")
else
labels=""
fi

image=""

for label in $labels; do
echo "Found label: $label"
case "$label" in
"subtensor-localnet:main")
image="ghcr.io/opentensor/subtensor-localnet:main"
break
;;
"subtensor-localnet:testnet")
image="ghcr.io/opentensor/subtensor-localnet:testnet"
break
;;
"subtensor-localnet:devnet")
image="ghcr.io/opentensor/subtensor-localnet:devnet"
break
;;
esac
done

if [[ -z "$image" ]]; then
# fallback to default based on branch
if [[ "${GITHUB_REF_NAME}" == "master" ]]; then
image="ghcr.io/opentensor/subtensor-localnet:main"
else
image="ghcr.io/opentensor/subtensor-localnet:devnet-ready"
fi
fi

echo "✅ Final selected image: $image"
echo "image=$image" >> "$GITHUB_OUTPUT"

- name: Log in to GitHub Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin

- name: Pull Docker Image
run: docker pull ${{ steps.set-image.outputs.image }}

- name: Save Docker Image to Cache
run: docker save -o subtensor-localnet.tar ${{ steps.set-image.outputs.image }}

- name: Upload Docker Image as Artifact
uses: actions/upload-artifact@v4
with:
name: subtensor-localnet
path: subtensor-localnet.tar

# Job to run tests in parallel
run-fast-blocks-e2e-test:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
name: "FB: ${{ matrix.test-file }} / Python ${{ matrix.python-version }}"
name: "${{ matrix.test.label }} / Py ${{ matrix.python-version }}"
needs:
- find-tests
- pull-docker-image
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false # Allow other matrix jobs to run even if this job fails
max-parallel: 32 # Set the maximum number of parallel jobs (same as we have cores in ubuntu-latest runner)
max-parallel: 64 # Set the maximum number of parallel jobs (same as we have cores in ubuntu-latest runner)
matrix:
os:
- ubuntu-latest
test-file: ${{ fromJson(needs.find-tests.outputs.test-files) }}
test: ${{ fromJson(needs.find-tests.outputs.test-files) }}
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- name: Check-out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
uses: astral-sh/setup-uv@v4

- name: install dependencies
run: uv sync --extra dev --dev

- name: Download Cached Docker Image
uses: actions/download-artifact@v4
with:
name: subtensor-localnet

- name: Load Docker Image
run: docker load -i subtensor-localnet.tar

- name: Run tests with retry
env:
LOCALNET_IMAGE_NAME: ${{ needs.pull-docker-image.outputs.image-name }}
run: |
for i in 1 2 3; do
echo "::group::🔁 Test attempt $i"
if uv run pytest ${{ matrix.test-file }} -s; then
if uv run pytest "${{ matrix.test.nodeid }}" -s; then
echo "✅ Tests passed on attempt $i"
echo "::endgroup::"
exit 0
else
echo "❌ Tests failed on attempt $i"
echo "::endgroup::"
if [ "$i" -lt 3 ]; then
echo "Retrying..."
sleep 5
fi
fi
done

echo "Tests failed after 3 attempts"
exit 1

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## 9.10.0 /2025-08-28

## What's Changed
* Fixes broken e2e tests by @thewhaleking in https://github.com/opentensor/bittensor/pull/3020
* Add async crv4 e2e test by @basfroman in https://github.com/opentensor/bittensor/pull/3022
* Use `TimelockedWeightCommits` instead of `CRV3WeightCommitsV2` by @basfroman in https://github.com/opentensor/bittensor/pull/3023
* fix: reflect correct return types for get_delegated by @Arthurdw in https://github.com/opentensor/bittensor/pull/3016
* Fix `flaky` e2e test (tests.e2e_tests.test_staking.test_safe_staking_scenarios) by @basfroman in https://github.com/opentensor/bittensor/pull/3025
* Separation of test modules into separate text elements as independent matrix elements by @basfroman in https://github.com/opentensor/bittensor/pull/3027
* Improve `move_stake` extrinsic (add `move_all_stake` parameter) by @basfroman in https://github.com/opentensor/bittensor/pull/3028
* Fix tests related with disabled `sudo_set_commit_reveal_weights_enabled` by @basfroman in https://github.com/opentensor/bittensor/pull/3026


**Full Changelog**: https://github.com/opentensor/bittensor/compare/v9.9.0...v9.10.0

## 9.9.0 /2025-08-11

## What's Changed
Expand Down
51 changes: 47 additions & 4 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ async def get_delegated(
block: Optional[int] = None,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> list[tuple[DelegateInfo, Balance]]:
) -> list[DelegatedInfo]:
"""
Retrieves a list of delegates and their associated stakes for a given coldkey. This function identifies the
delegates that a specific account has staked tokens on.
Expand All @@ -1892,7 +1892,7 @@ async def get_delegated(
reuse_block: Whether to reuse the last-used blockchain block hash.

Returns:
A list of tuples, each containing a delegate's information and staked amount.
A list containing the delegated information for the specified coldkey.

This function is important for account holders to understand their stake allocations and their involvement in
the network's delegation and consensus mechanisms.
Expand Down Expand Up @@ -2519,6 +2519,7 @@ async def get_next_epoch_start_block(
netuid=netuid, block=block, block_hash=block_hash, reuse_block=reuse_block
)

block = block or await self.substrate.get_block_number(block_hash=block_hash)
if block and blocks_since_last_step is not None and tempo:
return block - blocks_since_last_step + tempo + 1
return None
Expand Down Expand Up @@ -2747,6 +2748,45 @@ async def get_subnet_prices(
prices.update({0: Balance.from_tao(1)})
return prices

async def get_timelocked_weight_commits(
self,
netuid: int,
block: Optional[int] = None,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> list[tuple[str, int, str, int]]:
"""
Retrieves CRv4 weight commit information for a specific subnet.

Arguments:
netuid (int): The unique identifier of the subnet.
block (Optional[int]): The blockchain block number for the query. Default is ``None``.
block_hash: The hash of the block to retrieve the stake from. Do not specify if using block
or reuse_block
reuse_block: Whether to use the last-used block. Do not set if using block_hash or block.

Returns:
A list of commit details, where each item contains:
- ss58_address: The address of the committer.
- commit_block: The block number when the commitment was made.
- commit_message: The commit message.
- reveal_round: The round when the commitment was revealed.

The list may be empty if there are no commits found.
"""
block_hash = await self.determine_block_hash(
block=block, block_hash=block_hash, reuse_block=reuse_block
)
result = await self.substrate.query_map(
module="SubtensorModule",
storage_function="TimelockedWeightCommits",
params=[netuid],
block_hash=block_hash,
)

commits = result.records[0][1] if result.records else []
return [WeightCommitInfo.from_vec_u8_v2(commit) for commit in commits]

# TODO: remove unused parameters in SDK.v10
async def get_unstake_fee(
self,
Expand Down Expand Up @@ -4617,10 +4657,11 @@ async def move_stake(
origin_netuid: int,
destination_hotkey: str,
destination_netuid: int,
amount: Balance,
amount: Optional[Balance] = None,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
move_all_stake: bool = False,
) -> bool:
"""
Moves stake to a different hotkey and/or subnet.
Expand All @@ -4637,6 +4678,7 @@ async def move_stake(
period: The number of blocks during which the transaction will remain valid after it's
submitted. If the transaction is not included in a block within that number of blocks, it will expire
and be rejected. You can think of it as an expiration date for the transaction.
move_all_stake: If true, moves all stake from the source hotkey to the destination hotkey.

Returns:
success: True if the stake movement was successful.
Expand All @@ -4653,6 +4695,7 @@ async def move_stake(
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
move_all_stake=move_all_stake,
)

async def register(
Expand Down Expand Up @@ -5548,7 +5591,7 @@ async def unstake(
self,
wallet: "Wallet",
hotkey_ss58: Optional[str] = None,
netuid: Optional[int] = None,
netuid: Optional[int] = None, # TODO why is this optional?
amount: Optional[Balance] = None,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
Expand Down
39 changes: 25 additions & 14 deletions bittensor/core/extrinsics/asyncex/move_stake.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,28 +305,34 @@ async def move_stake_extrinsic(
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
move_all_stake: bool = False,
) -> bool:
"""
Moves stake from one hotkey to another within subnets in the Bittensor network.

Args:
subtensor (Subtensor): The subtensor instance to interact with the blockchain.
wallet (Wallet): The wallet containing the coldkey to authorize the move.
origin_hotkey (str): SS58 address of the origin hotkey associated with the stake.
origin_netuid (int): Network UID of the origin subnet.
destination_hotkey (str): SS58 address of the destination hotkey.
destination_netuid (int): Network UID of the destination subnet.
amount (Balance): The amount of stake to move as a `Balance` object.
wait_for_inclusion (bool): If True, waits for transaction inclusion in a block. Defaults to True.
wait_for_finalization (bool): If True, waits for transaction finalization. Defaults to False.
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
subtensor: The subtensor instance to interact with the blockchain.
wallet: The wallet containing the coldkey to authorize the move.
origin_hotkey: SS58 address of the origin hotkey associated with the stake.
origin_netuid: Network UID of the origin subnet.
destination_hotkey: SS58 address of the destination hotkey.
destination_netuid: Network UID of the destination subnet.
amount: The amount of stake to move as a `Balance` object.
wait_for_inclusion: If True, waits for transaction inclusion in a block. Defaults to True.
wait_for_finalization: If True, waits for transaction finalization. Defaults to False.
period: The number of blocks during which the transaction will remain valid after it's submitted. If the
transaction is not included in a block within that number of blocks, it will expire and be rejected. You can
think of it as an expiration date for the transaction.
move_all_stake: If true, moves all stake from the source hotkey to the destination hotkey.

Returns:
bool: True if the move was successful, False otherwise.
"""
amount.set_unit(netuid=origin_netuid)
if not amount and not move_all_stake:
logging.error(
":cross_mark: [red]Failed[/red]: Please specify an `amount` or `move_all_stake` argument to move stake."
)
return False

# Check sufficient stake
stake_in_origin, stake_in_destination = await _get_stake_in_origin_and_dest(
Expand All @@ -338,13 +344,18 @@ async def move_stake_extrinsic(
origin_netuid=origin_netuid,
destination_netuid=destination_netuid,
)
if stake_in_origin < amount:
if move_all_stake:
amount = stake_in_origin

elif stake_in_origin < amount:
logging.error(
f":cross_mark: [red]Failed[/red]: Insufficient stake in origin hotkey: {origin_hotkey}. "
f"Stake: {stake_in_origin}, amount: {amount}"
)
return False

amount.set_unit(netuid=origin_netuid)

try:
logging.info(
f"Moving stake from hotkey [blue]{origin_hotkey}[/blue] to hotkey [blue]{destination_hotkey}[/blue]\n"
Expand Down
8 changes: 7 additions & 1 deletion bittensor/core/extrinsics/asyncex/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import asyncio
from typing import Optional, Union, TYPE_CHECKING

from bittensor.core.extrinsics.asyncex.utils import get_extrinsic_fee
from bittensor.utils import unlock_key
from bittensor.utils.btlogging import logging
from bittensor.utils.registration import log_no_torch_error, create_pow_async, torch
Expand Down Expand Up @@ -57,6 +58,12 @@ async def _do_burned_register(
"hotkey": wallet.hotkey.ss58_address,
},
)
fee = await get_extrinsic_fee(
subtensor=subtensor, call=call, keypair=wallet.coldkeypub
)
logging.info(
f"The registration fee for SN #[blue]{netuid}[/blue] is [blue]{fee}[/blue]."
)
return await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
Expand Down Expand Up @@ -127,7 +134,6 @@ async def burned_register_extrinsic(
return True

logging.debug(":satellite: [magenta]Recycling TAO for Registration...[/magenta]")
logging.info(f"Recycling {recycle_amount} to register on subnet:{netuid}")

success, err_msg = await _do_burned_register(
subtensor=subtensor,
Expand Down
25 changes: 16 additions & 9 deletions bittensor/core/extrinsics/asyncex/unstaking.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Optional, TYPE_CHECKING

from async_substrate_interface.errors import SubstrateRequestException

from bittensor.core.extrinsics.asyncex.utils import get_extrinsic_fee
from bittensor.core.extrinsics.utils import get_old_stakes
from bittensor.utils import unlock_key, format_error_message
from bittensor.utils.balance import Balance
Expand Down Expand Up @@ -114,14 +114,14 @@ async def unstake_extrinsic(
else:
price_with_tolerance = base_price * (1 - rate_tolerance)

logging.info(
logging_info = (
f":satellite: [magenta]Safe Unstaking from:[/magenta] "
f"netuid: [green]{netuid}[/green], amount: [green]{unstaking_balance}[/green], "
f"tolerance percentage: [green]{rate_tolerance * 100}%[/green], "
f"price limit: [green]{price_with_tolerance}[/green], "
f"original price: [green]{base_price}[/green], "
f"with partial unstake: [green]{allow_partial_stake}[/green] "
f"on [blue]{subtensor.network}[/blue][magenta]...[/magenta]"
f"on [blue]{subtensor.network}[/blue]"
)

limit_price = Balance.from_tao(price_with_tolerance).rao
Expand All @@ -133,10 +133,10 @@ async def unstake_extrinsic(
)
call_function = "remove_stake_limit"
else:
logging.info(
logging_info = (
f":satellite: [magenta]Unstaking from:[/magenta] "
f"netuid: [green]{netuid}[/green], amount: [green]{unstaking_balance}[/green] "
f"on [blue]{subtensor.network}[/blue][magenta]...[/magenta]"
f"on [blue]{subtensor.network}[/blue]"
)
call_function = "remove_stake"

Expand All @@ -145,6 +145,10 @@ async def unstake_extrinsic(
call_function=call_function,
call_params=call_params,
)
fee = await get_extrinsic_fee(
subtensor=subtensor, call=call, keypair=wallet.coldkeypub, netuid=netuid
)
logging.info(f"{logging_info} for fee [blue]{fee}[/blue][magenta]...[/magenta]")
success, message = await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
Expand Down Expand Up @@ -381,10 +385,6 @@ async def unstake_multiple_extrinsic(
continue

try:
logging.info(
f"Unstaking [blue]{unstaking_balance}[/blue] from hotkey: [magenta]{hotkey_ss58}[/magenta] on netuid: "
f"[blue]{netuid}[/blue]"
)
call = await subtensor.substrate.compose_call(
call_module="SubtensorModule",
call_function="remove_stake",
Expand All @@ -394,6 +394,13 @@ async def unstake_multiple_extrinsic(
"netuid": netuid,
},
)
fee = await get_extrinsic_fee(
subtensor=subtensor, call=call, keypair=wallet.coldkeypub, netuid=netuid
)
logging.info(
f"Unstaking [blue]{unstaking_balance}[/blue] from hotkey: [magenta]{hotkey_ss58}[/magenta] on netuid: "
f"[blue]{netuid}[/blue] for fee [blue]{fee}[/blue]"
)

staking_response, err_msg = await subtensor.sign_and_send_extrinsic(
call=call,
Expand Down
Loading
Loading