Skip to content

Commit 3835390

Browse files
authored
Merge pull request #2860 from opentensor/feat/roman/add-non-fast-block-tests-each-saturday
Add `non-fast-blocks` e2e tests each Saturday
2 parents 55ab373 + ef2edcf commit 3835390

15 files changed

+342
-141
lines changed

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

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
run: |
4444
test_files=$(find tests/e2e_tests -name "test*.py" | jq -R -s -c 'split("\n") | map(select(. != ""))')
4545
# keep it here for future debug
46-
# test_files=$(find tests/e2e_tests -type f -name "test*.py" | grep -E 'test_(incentive|commit_weights|set_weights)\.py$' | jq -R -s -c 'split("\n") | map(select(. != ""))')
46+
# 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(. != ""))')
4747
echo "test-files=$test_files" >> "$GITHUB_OUTPUT"
4848
shell: bash
4949

@@ -66,8 +66,8 @@ jobs:
6666
path: subtensor-localnet.tar
6767

6868
# Job to run tests in parallel
69-
run-e2e-test:
70-
name: ${{ matrix.test-file }} / Python ${{ matrix.python-version }}
69+
run-fast-blocks-e2e-test:
70+
name: "FB: ${{ matrix.test-file }} / Python ${{ matrix.python-version }}"
7171
needs:
7272
- find-tests
7373
- pull-docker-image
@@ -127,3 +127,76 @@ jobs:
127127
sleep 5
128128
fi
129129
done
130+
131+
132+
cron-run-non-fast-blocks-e2e-test:
133+
if: github.event_name == 'schedule'
134+
name: "NFB: ${{ matrix.test-file }} / Python ${{ matrix.python-version }}"
135+
needs:
136+
- find-tests
137+
- pull-docker-image
138+
runs-on: ubuntu-latest
139+
timeout-minutes: 1440
140+
141+
strategy:
142+
fail-fast: false # Allow other matrix jobs to run even if this job fails
143+
max-parallel: 32 # Set the maximum number of parallel jobs (same as we have cores in ubuntu-latest runner)
144+
matrix:
145+
os:
146+
- ubuntu-latest
147+
test-file: ${{ fromJson(needs.find-tests.outputs.test-files) }}
148+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
149+
150+
steps:
151+
- name: Check if today is Saturday
152+
run: |
153+
day=$(date -u +%u)
154+
echo "Today is weekday $day"
155+
if [ "$day" -ne 6 ]; then
156+
echo "⏭️ Skipping: not Saturday"
157+
exit 78
158+
fi
159+
- name: Check-out repository
160+
uses: actions/checkout@v4
161+
162+
- name: Set up Python ${{ matrix.python-version }}
163+
uses: actions/setup-python@v5
164+
with:
165+
python-version: ${{ matrix.python-version }}
166+
167+
- name: Install uv
168+
uses: astral-sh/setup-uv@v4
169+
170+
- name: install dependencies
171+
run: uv sync --extra dev --dev
172+
173+
- name: Download Cached Docker Image
174+
uses: actions/download-artifact@v4
175+
with:
176+
name: subtensor-localnet
177+
178+
- name: Load Docker Image
179+
run: docker load -i subtensor-localnet.tar
180+
181+
- name: Run patched E2E tests
182+
env:
183+
FAST_BLOCKS: "0"
184+
run: |
185+
set +e
186+
for i in 1 2 3; do
187+
echo "🔁 Attempt $i: Running tests"
188+
uv run pytest ${{ matrix.test-file }} -s
189+
status=$?
190+
if [ $status -eq 0 ]; then
191+
echo "✅ Tests passed on attempt $i"
192+
break
193+
else
194+
echo "❌ Tests failed on attempt $i"
195+
if [ $i -eq 3 ]; then
196+
echo "Tests failed after 3 attempts"
197+
exit 1
198+
fi
199+
echo "Retrying..."
200+
sleep 5
201+
fi
202+
done

bittensor/core/async_subtensor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,6 +2488,12 @@ async def immunity_period(
24882488
)
24892489
return None if call is None else int(call)
24902490

2491+
async def is_fast_blocks(self):
2492+
"""Returns True if the node is running with fast blocks. False if not."""
2493+
return (
2494+
await self.query_constant("SubtensorModule", "DurationOfStartCall")
2495+
).value == 10
2496+
24912497
async def is_hotkey_delegate(
24922498
self,
24932499
hotkey_ss58: str,

bittensor/core/subtensor.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,10 @@ def immunity_period(
19711971
)
19721972
return None if call is None else int(call)
19731973

1974+
def is_fast_blocks(self):
1975+
"""Returns True if the node is running with fast blocks. False if not."""
1976+
return self.query_constant("SubtensorModule", "DurationOfStartCall").value == 10
1977+
19741978
def is_hotkey_delegate(self, hotkey_ss58: str, block: Optional[int] = None) -> bool:
19751979
"""
19761980
Determines whether a given hotkey (public key) is a delegate on the Bittensor network. This function checks if

bittensor/core/subtensor_api/chain.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]):
1414
self.get_minimum_required_stake = subtensor.get_minimum_required_stake
1515
self.get_vote_data = subtensor.get_vote_data
1616
self.get_timestamp = subtensor.get_timestamp
17+
self.is_fast_blocks = subtensor.is_fast_blocks
1718
self.last_drand_round = subtensor.last_drand_round
1819
self.state_call = subtensor.state_call
1920
self.tx_rate_limit = subtensor.tx_rate_limit

bittensor/core/subtensor_api/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def add_legacy_methods(subtensor: "SubtensorApi"):
101101
subtensor.get_unstake_fee = subtensor._subtensor.get_unstake_fee
102102
subtensor.get_vote_data = subtensor._subtensor.get_vote_data
103103
subtensor.immunity_period = subtensor._subtensor.immunity_period
104+
subtensor.is_fast_blocks = subtensor._subtensor.is_fast_blocks
104105
subtensor.is_hotkey_delegate = subtensor._subtensor.is_hotkey_delegate
105106
subtensor.is_hotkey_registered = subtensor._subtensor.is_hotkey_registered
106107
subtensor.is_hotkey_registered_any = subtensor._subtensor.is_hotkey_registered_any

tests/e2e_tests/conftest.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,13 @@ def stop_existing_test_containers():
206206
"9944:9944",
207207
"-p",
208208
"9945:9945",
209-
LOCALNET_IMAGE_NAME,
210-
params,
209+
str(LOCALNET_IMAGE_NAME),
211210
]
212211

212+
cmds += params.split() if params else []
213+
214+
print("Entire run command: ", cmds)
215+
213216
try_start_docker()
214217

215218
stop_existing_test_containers()
@@ -275,7 +278,19 @@ def bob_wallet():
275278
return wallet
276279

277280

281+
@pytest.fixture
282+
def charlie_wallet():
283+
keypair, wallet = setup_wallet("//Charlie")
284+
return wallet
285+
286+
278287
@pytest.fixture
279288
def dave_wallet():
280289
keypair, wallet = setup_wallet("//Dave")
281290
return wallet
291+
292+
293+
@pytest.fixture
294+
def eve_wallet():
295+
keypair, wallet = setup_wallet("//Eve")
296+
return wallet

tests/e2e_tests/test_commit_reveal_v3.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,22 @@ async def test_commit_and_reveal_weights_cr3(local_chain, subtensor, alice_walle
3030
Raises:
3131
AssertionError: If any of the checks or verifications fail
3232
"""
33-
BLOCK_TIME = 0.25 # 12 for non-fast-block, 0.25 for fast block
34-
netuid = 2
33+
BLOCK_TIME = (
34+
0.25 if subtensor.is_fast_blocks() else 12.0
35+
) # 12 for non-fast-block, 0.25 for fast block
36+
netuid = subtensor.get_total_subnets() # 2
37+
3538
logging.console.info("Testing test_commit_and_reveal_weights")
3639

3740
# Register root as Alice
3841
assert subtensor.register_subnet(alice_wallet), "Unable to register the subnet"
3942

4043
# Verify subnet 2 created successfully
41-
assert subtensor.subnet_exists(netuid), "Subnet wasn't created successfully"
44+
assert subtensor.subnet_exists(netuid), (
45+
f"Subnet {netuid} wasn't created successfully"
46+
)
4247

43-
logging.console.info("Subnet 2 is registered")
48+
logging.console.success(f"Subnet {netuid} is registered")
4449

4550
# Enable commit_reveal on the subnet
4651
assert sudo_set_hyperparameter_bool(
@@ -74,7 +79,7 @@ async def test_commit_and_reveal_weights_cr3(local_chain, subtensor, alice_walle
7479
logging.console.info("sudo_set_weights_set_rate_limit executed: set to 0")
7580

7681
# Change the tempo of the subnet
77-
tempo_set = 50
82+
tempo_set = 50 if subtensor.is_fast_blocks() else 10
7883
assert (
7984
sudo_set_admin_utils(
8085
local_chain,
@@ -103,7 +108,7 @@ async def test_commit_and_reveal_weights_cr3(local_chain, subtensor, alice_walle
103108
)
104109

105110
# Wait for 2 tempos to pass as CR3 only reveals weights after 2 tempos + 1
106-
subtensor.wait_for_block((tempo_set * 2) + 1)
111+
subtensor.wait_for_block(tempo_set * 2 + 1)
107112

108113
# Lower than this might mean weights will get revealed before we can check them
109114
if upcoming_tempo - current_block < 3:
@@ -117,7 +122,7 @@ async def test_commit_and_reveal_weights_cr3(local_chain, subtensor, alice_walle
117122
latest_drand_round = subtensor.last_drand_round()
118123
upcoming_tempo = next_tempo(current_block, tempo)
119124
logging.console.info(
120-
f"Post first wait_interval (to ensure window isnt too low): {current_block}, next tempo: {upcoming_tempo}, drand: {latest_drand_round}"
125+
f"Post first wait_interval (to ensure window isn't too low): {current_block}, next tempo: {upcoming_tempo}, drand: {latest_drand_round}"
121126
)
122127

123128
# Commit weights
@@ -171,6 +176,7 @@ async def test_commit_and_reveal_weights_cr3(local_chain, subtensor, alice_walle
171176
subtensor,
172177
netuid=netuid,
173178
reporting_interval=1,
179+
sleep=BLOCK_TIME,
174180
)
175181

176182
# Fetch the latest drand pulse

tests/e2e_tests/test_commit_weights.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ async def test_commit_and_reveal_weights_legacy(local_chain, subtensor, alice_wa
2727
AssertionError: If any of the checks or verifications fail
2828
"""
2929
netuid = subtensor.get_total_subnets() # 2
30-
30+
set_tempo = 100 if subtensor.is_fast_blocks() else 10
3131
print("Testing test_commit_and_reveal_weights")
3232

3333
# Register root as Alice
@@ -78,7 +78,7 @@ async def test_commit_and_reveal_weights_legacy(local_chain, subtensor, alice_wa
7878
call_function="sudo_set_tempo",
7979
call_params={
8080
"netuid": netuid,
81-
"tempo": 100,
81+
"tempo": set_tempo,
8282
},
8383
)
8484

@@ -165,11 +165,11 @@ async def test_commit_weights_uses_next_nonce(local_chain, subtensor, alice_wall
165165
Raises:
166166
AssertionError: If any of the checks or verifications fail
167167
"""
168-
subnet_tempo = 50
168+
subnet_tempo = 50 if subtensor.is_fast_blocks() else 10
169169
netuid = subtensor.get_total_subnets() # 2
170170

171171
# Wait for 2 tempos to pass as CR3 only reveals weights after 2 tempos
172-
subtensor.wait_for_block(subnet_tempo * 2 + 1)
172+
subtensor.wait_for_block(subtensor.block + (subnet_tempo * 2) + 1)
173173

174174
print("Testing test_commit_and_reveal_weights")
175175
# Register root as Alice
@@ -267,16 +267,22 @@ def send_commit(salt_, weight_uids_, weight_vals_):
267267

268268
send_commit(salt, weight_uids, weight_vals)
269269

270-
# let's wait for 3 (12 fast blocks) seconds between transactions
271-
subtensor.wait_for_block(subtensor.block + 12)
270+
# let's wait for 3 (12 fast blocks) seconds between transactions, next block for non-fast-blocks
271+
waiting_block = (subtensor.block + 12) if subtensor.is_fast_blocks() else None
272+
subtensor.wait_for_block(waiting_block)
272273

273274
logging.console.info(
274275
f"[orange]Nonce after third commit_weights: "
275276
f"{subtensor.substrate.get_account_next_index(alice_wallet.hotkey.ss58_address)}[/orange]"
276277
)
277278

278279
# Wait a few blocks
279-
subtensor.wait_for_block(subtensor.block + subtensor.tempo(netuid) * 2)
280+
waiting_block = (
281+
(subtensor.block + subtensor.tempo(netuid) * 2)
282+
if subtensor.is_fast_blocks()
283+
else None
284+
)
285+
subtensor.wait_for_block(waiting_block)
280286

281287
# Query the WeightCommits storage map for all three salts
282288
weight_commits = subtensor.query_module(

tests/e2e_tests/test_commitment.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
from bittensor import logging
55
from tests.e2e_tests.utils.chain_interactions import sudo_set_admin_utils
6-
from tests.e2e_tests.utils.e2e_test_utils import wait_to_start_call
6+
from tests.e2e_tests.utils.e2e_test_utils import (
7+
wait_to_start_call,
8+
async_wait_to_start_call,
9+
)
710

811
logging.set_trace()
912

@@ -15,7 +18,7 @@ def test_commitment(local_chain, subtensor, alice_wallet, dave_wallet):
1518
"Subnet wasn't created successfully"
1619
)
1720

18-
assert wait_to_start_call(subtensor, dave_wallet, dave_subnet_netuid, 10)
21+
assert wait_to_start_call(subtensor, dave_wallet, dave_subnet_netuid)
1922

2023
with pytest.raises(SubstrateRequestException, match="AccountNotAllowedCommit"):
2124
subtensor.set_commitment(
@@ -93,11 +96,9 @@ async def test_commitment_async(
9396
"Subnet wasn't created successfully"
9497
)
9598

96-
await async_subtensor.wait_for_block(await async_subtensor.block + 20)
97-
status, message = await async_subtensor.start_call(
98-
dave_wallet, dave_subnet_netuid, True, True
99+
assert await async_wait_to_start_call(
100+
async_subtensor, dave_wallet, dave_subnet_netuid
99101
)
100-
assert status, message
101102

102103
async with async_subtensor as sub:
103104
with pytest.raises(SubstrateRequestException, match="AccountNotAllowedCommit"):

tests/e2e_tests/test_delegate.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def test_change_take(local_chain, subtensor, alice_wallet, bob_wallet):
171171

172172

173173
@pytest.mark.asyncio
174-
async def test_delegates(subtensor, alice_wallet, bob_wallet):
174+
async def test_delegates(local_chain, subtensor, alice_wallet, bob_wallet):
175175
"""
176176
Tests:
177177
- Check default Delegates
@@ -240,6 +240,7 @@ async def test_delegates(subtensor, alice_wallet, bob_wallet):
240240
assert subtensor.get_delegated(bob_wallet.coldkey.ss58_address) == []
241241

242242
alice_subnet_netuid = subtensor.get_total_subnets() # 2
243+
set_tempo = 10
243244
# Register a subnet, netuid 2
244245
assert subtensor.register_subnet(alice_wallet), "Subnet wasn't created"
245246

@@ -250,6 +251,17 @@ async def test_delegates(subtensor, alice_wallet, bob_wallet):
250251

251252
assert wait_to_start_call(subtensor, alice_wallet, alice_subnet_netuid)
252253

254+
# set the same tempo for both type of nodes (fast and non-fast blocks)
255+
assert (
256+
sudo_set_admin_utils(
257+
local_chain,
258+
alice_wallet,
259+
call_function="sudo_set_tempo",
260+
call_params={"netuid": alice_subnet_netuid, "tempo": set_tempo},
261+
)[0]
262+
is True
263+
)
264+
253265
subtensor.add_stake(
254266
bob_wallet,
255267
alice_wallet.hotkey.ss58_address,
@@ -259,6 +271,9 @@ async def test_delegates(subtensor, alice_wallet, bob_wallet):
259271
wait_for_finalization=True,
260272
)
261273

274+
# let chain update validator_permits
275+
subtensor.wait_for_block(subtensor.block + set_tempo + 1)
276+
262277
bob_delegated = subtensor.get_delegated(bob_wallet.coldkey.ss58_address)
263278
assert bob_delegated == [
264279
DelegatedInfo(
@@ -272,9 +287,10 @@ async def test_delegates(subtensor, alice_wallet, bob_wallet):
272287
bob_delegated[0].total_daily_return.rao
273288
),
274289
netuid=alice_subnet_netuid,
275-
stake=get_dynamic_balance(bob_delegated[0].stake.rao),
290+
stake=get_dynamic_balance(bob_delegated[0].stake.rao, alice_subnet_netuid),
276291
),
277292
]
293+
bittensor.logging.console.success("Test [green]test_delegates[/green] passed.")
278294

279295

280296
def test_nominator_min_required_stake(local_chain, subtensor, alice_wallet, bob_wallet):

0 commit comments

Comments
 (0)