Skip to content

Fix reuse_block=True raising in async reads#3370

Open
Yupsecous wants to merge 1 commit into
latent-to:stagingfrom
Yupsecous:fix/yupsecous/h1-reuse-block
Open

Fix reuse_block=True raising in async reads#3370
Yupsecous wants to merge 1 commit into
latent-to:stagingfrom
Yupsecous:fix/yupsecous/h1-reuse-block

Conversation

@Yupsecous
Copy link
Copy Markdown

Fix reuse_block=True raising ValueError across async read methods

Base branch: staging. No separate issue — the bug is described in full below
(per maintainer guidance that a detailed PR description suffices).

Bug

reuse_block=True raises ValueError: Cannot specify both reuse_block and block_hash/block for ~23 AsyncSubtensor read methods after any prior chain
query. No separate issue was filed; the full reproduction, root cause, and fix
are described below.

Description of the Change

determine_block_hash(reuse_block=True) returns substrate.last_block_hash
(non-None after any prior query). Many methods resolved block_hash once and
then forwarded both the resolved block_hash and reuse_block into a
child helper, whose own determine_block_hash then hit its mutual-exclusion
guard and raised.

This change forwards only the already-resolved block_hash to the child
(dropping the now-redundant block/reuse_block) at all 25 affected call
sites across 23 methods
— e.g. difficulty, tempo, immunity_period,
get_delegate_take, get_root_claimable_stake,
get_neuron_for_pubkey_and_subnet, is_hotkey_delegate,
filter_netuids_by_registered_hotkeys, compose_call. Every forwarded child was
verified to use block/reuse_block only for hash resolution, so passing
only block_hash loses no information.

Alternate Designs

Relaxing determine_block_hash's guard to tolerate reuse_block together with a
matching block_hash was rejected: the guard is documented, intended validation,
and the real defect is the double-resolution at the call sites, not the guard.

Possible Drawbacks

None expected. Behavior is unchanged for the block, block_hash, and default
(no-arg) paths; only the previously-broken reuse_block=True path changes (from
raising to returning data). Two look-alikes were deliberately left unchanged:
get_liquidity_list (its query_map runs before resolution, so it already
forwards raw args and resolves once) and
is_in_admin_freeze_windowget_next_epoch_start_block (which reads the raw
block number for its return value, so it must keep raw args).

Verification Process

  • Repro-first: a new parametrized regression test fails on staging with the
    ValueError for every affected method, and passes with the fix.
  • tests/unit_tests/test_async_subtensor_reuse_block.py drives the real
    determine_block_hash path (the resolving child is not mocked) across all
    23 methods, asserting (a) no guard ValueError, (b) determine_block_hash
    never re-receives the guard-tripping combination, and (c) the reused
    last_block_hash threads to the leaf substrate call. Adds a no-cached-block
    edge case and a block_hash-equivalence check.
  • A few existing assertions that encoded the old (buggy) call signature were
    updated to the corrected signature; all result == ... output assertions were
    left unchanged.
  • Python 3.12, async-substrate-interface 2.1.0: test_async_subtensor.py + new
    file → 262 passed; full tests/unit_tests1169 passed (the only
    failures are 3 pre-existing, unrelated environment issues — two test_dendrite
    on aiohttp 3.14, one needing the torch extra — identical on pristine
    staging); ruff format --check, ruff check, mypy clean.

Release Notes

Fixed reuse_block=True raising ValueError on many AsyncSubtensor read
methods (e.g. difficulty, tempo, get_delegate_take).

Branch Acknowledgement

[x] I am acknowledging that I am opening this branch against staging

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should really live within test_async_subtensor.py, and probably doesn't need to be so verbose.

Many AsyncSubtensor methods resolved block_hash and then forwarded both
the resolved block_hash and reuse_block into a child that re-resolved,
tripping determine_block_hash's mutual-exclusion guard (ValueError:
Cannot specify both reuse_block and block_hash/block). So
reuse_block=True raised for ~23 public read methods after any
prior query.

Forward only the resolved block_hash to the child (dropping the
now-redundant block/reuse_block) across all 25 affected call sites.
Behavior-preserving for the block/block_hash/default paths; adds
regression tests covering reuse_block=True for every affected method.
@Yupsecous Yupsecous force-pushed the fix/yupsecous/h1-reuse-block branch from 07ebf67 to 29ccfdb Compare June 3, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants