Skip to content

Convert transaction extensions to dispatch extensions#2773

Open
l0r1s wants to merge 15 commits into
devnet-readyfrom
tx-ext-to-dispatch-ext
Open

Convert transaction extensions to dispatch extensions#2773
l0r1s wants to merge 15 commits into
devnet-readyfrom
tx-ext-to-dispatch-ext

Conversation

@l0r1s

@l0r1s l0r1s commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR moves Subtensor-specific pre-dispatch checks out of SubtensorTransactionExtension and into FRAME DispatchExtensions.

The dispatch extensions are now the source of truth for these checks, so they run for both top-level extrinsics and nested dispatch paths such as proxies and precompile-dispatched runtime calls. SubtensorTransactionExtension remains only as a transaction-pool adapter for top-level validation, including Pays::No admission checks.

Changes

  • Added dedicated Subtensor dispatch extensions:
    • CheckWeights: input length checks, minimum stake checks, commit/reveal validation, and invalid reveal-round checks.
    • CheckRateLimits: weight commit/set rate limits and network registration rate limits.
    • CheckDelegateTake: delegate-take bounds and hotkey owner checks.
    • CheckServingEndpoints: axon, axon TLS, and prometheus serving endpoint validation.
    • CheckEvmKeyAssociation: subnet UID existence and EVM-key association cooldown checks.
  • Kept CheckColdkeySwap as a dispatch extension and expanded tests to cover direct, proxied, and nested-proxy execution paths.
  • Wired all Subtensor dispatch extensions into frame_system::Config::DispatchExtension as a tuple in the runtime and test runtimes.
  • Simplified SubtensorTransactionExtension:
    • Removes duplicated rule-specific validation logic.
    • Calls the configured runtime dispatch extension from validate.
    • Maps Subtensor pallet DispatchError::Module values into CustomTransactionError.
  • Simplified precompile dispatch:
    • Removes manual SubtensorTransactionExtension validate/prepare/post-dispatch calls.
    • Relies on normal call.dispatch(origin), which invokes dispatch extensions.
  • Moved rule-specific tests into the corresponding dispatch extension files.
  • Deleted the old transaction_extension_pays_no test module and colocated transaction-extension adapter tests with SubtensorTransactionExtension.
  • Removed legacy transaction-extension validation tests from serving and weights tests where the same behavior is now covered by dispatch-extension tests.

@l0r1s l0r1s added the skip-cargo-audit This PR fails cargo audit but needs to be merged anyway label Jun 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

eco-tests changed — indexer review required

This PR modifies files under eco-tests/. and may affect downstream indexing.
cc @evgeny-s — please review manually

Changed files
  • eco-tests/src/mock.rs

@github-actions github-actions Bot requested a review from evgeny-s June 21, 2026 22:40

@github-actions github-actions Bot left a comment

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.

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

}

fn commit_epoch(hash: H256) -> Result<u64, Error<T>> {
Pallet::<T>::find_commit_epoch_via_hash(hash).ok_or(Error::<T>::NoWeightsCommitFound)

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.

[HIGH] Unbounded commit scan now runs during dispatch

commit_epoch() calls Pallet::<T>::find_commit_epoch_via_hash, which is implemented as WeightCommits::<T>::iter() over all stored commits. Because this helper now runs from CheckWeights::pre_dispatch, every reveal_weights, reveal_mechanism_weights, and each item in batch_reveal_weights can perform a global storage scan during block execution, proxy dispatch, or EVM-precompile dispatch. The extension weight is fixed, so a staked caller can force work proportional to global commit storage while paying only the normal fixed/no-fee reveal weight, creating a block-weight underestimation and DoS path.

Bound this check to the caller's own commit queue, e.g. read WeightCommits for (netuid_index, who) and search that bounded deque, matching the dispatch body's logic. Alternatively, keep the global pre-admission scan only in the transaction-pool adapter and rely on the dispatch body for execution-time validation.

@github-actions

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: VULNERABLE

BASELINE scrutiny: l0r1s has write permission, a long-lived account, substantive prior subtensor history, and no Gittensor allowlist hit; branch tx-ext-to-dispatch-ext -> devnet-ready.

No .github/ai-review, copilot-instruction, dependency manifest, or lockfile changes were present.

Findings

Sev File Finding
HIGH pallets/subtensor/src/guards/check_weights.rs:103 Unbounded commit scan now runs during dispatch inline

Conclusion

This looks like a legitimate refactor, but moving the reveal commit lookup into a runtime DispatchExtension introduces an under-weighted unbounded storage scan during dispatch. That is a runtime DoS risk, so the PR is vulnerable until the reveal checks are bounded to the caller's own commit queue or kept out of block execution.


# 🔍 AI Review — Auditor (domain review) has not yet run on this PR.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-cargo-audit This PR fails cargo audit but needs to be merged anyway

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant