Skip to content

Handle dust in order_swap.rs and leasing.rs to sync TI#2754

Open
gztensor wants to merge 5 commits into
devnet-readyfrom
fix/dust-handling
Open

Handle dust in order_swap.rs and leasing.rs to sync TI#2754
gztensor wants to merge 5 commits into
devnet-readyfrom
fix/dust-handling

Conversation

@gztensor

Copy link
Copy Markdown
Contributor

Description

When Currency:: is directly used to transfer or withdraw TAO, it may burn dust and not decrease subtensor pallet total issuance. Fixing all across codebase.

Related Issue(s)

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have run ./scripts/fix_rust.sh to ensure my code is formatted and linted correctly
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@gztensor gztensor self-assigned this Jun 12, 2026
@gztensor gztensor added the skip-cargo-audit This PR fails cargo audit but needs to be merged anyway label Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: SAFE

BASELINE scrutiny: gztensor has repo write permission, matching PR author/commit author identity, substantial contribution history, and no trusted Gittensor allowlist hit; branch fix/dust-handling -> devnet-ready.

Static review of the pre-fetched diff found no changes to .github/ai-review/*, .github/copilot-instructions.md, dependencies, lockfiles, build scripts, or new privileged entry points. The pallet changes route existing TAO transfers through the existing Pallet::transfer_tao helper so Balances-side dust burns are mirrored into Subtensor total issuance, and the runtime-facing change includes a spec_version bump. The prior Skeptic sticky was already SAFE and contained no finding IDs to reconcile.

Findings

No findings.

Conclusion

No malicious behavior or Skeptic-level security vulnerability was found in the diff. The bounded leasing weight/accounting calibration concern remains domain-review territory rather than a maliciousness or direct security finding here.


🔍 AI Review — Auditor (domain review)

VERDICT: 👎

Gittensor association: LIKELY by heuristic; author is not allowlisted, but has write permission and extensive recent subtensor PR history.

No auto-fixes were applied. spec_version is already bumped to 426, and I did not run tests because the blocking issue is visible statically.

Duplicate-work check: PR #2707 overlaps on the same dust/issuance problem with a broader runtime-level DustRemoval approach. For the targeted order-swap/leasing fix in #2738, this PR is the better candidate once the leasing weight is corrected; do not merge both approaches independently.

Findings

Sev File Finding
HIGH pallets/subtensor/src/subnets/leasing.rs:149 Update leasing weight for contributor refund issuance accounting inline
LOW pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs:868 Restore the already-registered hotkey test case inline

Prior-comment reconciliation

  • 3fdd1365: not addressed — The contributor refund loop still calls transfer_tao without a corresponding register_leased_network(k) weight update.

Conclusion

Blocking because the leasing contributor refund path still adds TAO-transfer issuance accounting inside a contributor-scaled loop without updating the extrinsic weight. The unrelated hotkey-swap test change should also be restored so it keeps covering the error path named by the test.


📜 Previous run (superseded)
Sev File Finding Status
HIGH pallets/subtensor/src/subnets/leasing.rs:149 Update leasing weight for contributor refund issuance accounting ➡️ Carried forward to current findings
The contributor refund loop still calls transfer_tao without a corresponding register_leased_network(k) weight update.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@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.

contributor_refund.into(),
Preservation::Expendable,
)?;
Self::transfer_tao(&lease_coldkey, &contributor, contributor_refund.into())?;

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] Update leasing weight for per-contributor issuance accounting

This refund loop now calls Self::transfer_tao, which does more storage work than the previous direct Currency::transfer: it checks the source balance, reads Balances total issuance before and after, and can mutate Subtensor TotalIssuance when dust is burned. Because this runs once per contributor, register_leased_network(k) gained O(k) additional reads and possible writes, but SubnetLeasingWeightInfo::do_register_leased_network and the generated benchmark weight were not updated. Re-benchmark/update the weight or manually add the extra DB reads/writes so the extrinsic is not underweighted at high MaxContributors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Bad review. Direct Currency::transfer does not update subtensor pallet TotalIssuance if it burns dust.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

JohnReedV
JohnReedV previously approved these changes Jun 12, 2026

@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.

contributor_refund.into(),
Preservation::Expendable,
)?;
Self::transfer_tao(&lease_coldkey, &contributor, contributor_refund.into())?;

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] Update leasing weight for contributor refund issuance accounting

This still routes each contributor refund through transfer_tao, but the PR does not update the register_leased_network(k) benchmark/weight. Compared with the old raw Currency::transfer, transfer_tao performs additional total-issuance accounting on every refund and can write Subtensor TotalIssuance when dust is reaped. Because this call sits inside the contributor-scaled loop, the extrinsic weight needs to be regenerated or manually adjusted for the new worst-case storage work.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

l0r1s
l0r1s previously approved these changes Jun 18, 2026

@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.

contributor_refund.into(),
Preservation::Expendable,
)?;
Self::transfer_tao(&lease_coldkey, &contributor, contributor_refund.into())?;

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] Update leasing weight for contributor refund issuance accounting

register_leased_network is still charged from the existing generated weight, but this line now calls Self::transfer_tao once per refunded contributor. That helper adds balance/issuance reads and can mutate TotalIssuance when dust is burned; none of that extra work is reflected in pallets/subtensor/src/weights.rs. Because this loop scales up to T::MaxContributors, the extrinsic can be undercharged on the worst-case path. Re-run the benchmark or explicitly update the generated register_leased_network(k) weight/proof comments to include the new per-contributor accounting.

Comment on lines 847 to +868
@@ -864,7 +865,7 @@ fn test_swap_owner_new_hotkey_already_exists() {
Some(netuid),
false
),
Error::<Test>::HotKeyAlreadyRegisteredInSubNet
Error::<Test>::NonAssociatedColdKey

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.

[LOW] Restore the already-registered hotkey test case

This test is named and documented as covering HotKeyAlreadyRegisteredInSubNet, but the new setup no longer registers new_hotkey on netuid and now asserts NonAssociatedColdKey instead. That silently removes coverage for the already-registered branch while leaving the old test name/comment in place. Restore the original setup so new_hotkey is registered on the target subnet and old_hotkey is merely owned by the caller.

Suggested change
let netuid = add_dynamic_network(&new_hotkey, &coldkey);
add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_u64.into());
// old_hotkey is owned by coldkey; new_hotkey was already registered on `netuid`
// by add_dynamic_network (the condition under test). Do NOT reassign new_hotkey to
// a foreign coldkey — the new_hotkey-ownership check (NonAssociatedColdKey) would
// then fire before the already-registered-in-subnet check this test targets.
Owner::<Test>::insert(old_hotkey, coldkey);
// Perform the swap
System::set_block_number(System::block_number() + HotkeySwapOnSubnetInterval::get());
assert_err!(
SubtensorModule::do_swap_hotkey(
RuntimeOrigin::signed(coldkey),
&old_hotkey,
&new_hotkey,
Some(netuid),
false
),
Error::<Test>::HotKeyAlreadyRegisteredInSubNet

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

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.

3 participants