From 7dc87032f79e6431295dcd4ee0a865313752f326 Mon Sep 17 00:00:00 2001 From: Loom Agent Date: Sun, 12 Jul 2026 21:38:38 +0000 Subject: [PATCH] fix(subtensor): wire migrate_cleanup_swap_v3 into on_runtime_upgrade (#2793) migrate_cleanup_swap_v3 is declared and unit-tested but wired into neither the pallet on_runtime_upgrade chain nor the runtime Migrations tuple, so it never runs. After reserve() dropped the SubnetTaoProvided/SubnetAlphaInProvided addend, the residual on every affected subnet is never folded into the main reserves, so the upgrade drops reserve() by exactly that residual and jumps the AMM spot price discontinuously (consensus- and money-affecting; feeds every add/remove/move_stake, dividends, and limit-order quotes). Wire it at the end of the pallet on_runtime_upgrade chain, consistent with the other subtensor migrations; its HasMigrationRun guard keeps it idempotent. Add a regression test that drives the upgrade hook and asserts the residual is folded. Bump spec_version 428 -> 429. --- pallets/subtensor/src/macros/hooks.rs | 7 ++++- pallets/subtensor/src/tests/migration.rs | 40 ++++++++++++++++++++++++ runtime/src/lib.rs | 2 +- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index ed0b46314b..fbf7f74702 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -179,7 +179,12 @@ mod hooks { // Fix lock state left behind by subnet-scoped hotkey swaps. .saturating_add(migrations::migrate_fix_subnet_hotkey_lock_swaps::migrate_fix_subnet_hotkey_lock_swaps::()) // Populate reverse lookup index for EVM address associations. - .saturating_add(migrations::migrate_associated_evm_address_index::migrate_associated_evm_address_index::()); + .saturating_add(migrations::migrate_associated_evm_address_index::migrate_associated_evm_address_index::()) + // Fold the deprecated SubnetTaoProvided / SubnetAlphaInProvided residuals into the + // main AMM reserves (issue #2793). reserve() dropped the *Provided addend, so this + // migration must run at upgrade to keep reserves / spot price continuous. It is + // HasMigrationRun-guarded and idempotent. + .saturating_add(migrations::migrate_cleanup_swap_v3::migrate_cleanup_swap_v3::()); weight } diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index 133934c93f..9ecd89c713 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -3342,6 +3342,46 @@ fn test_migrate_cleanup_swap_v3() { }); } +// Regression test for issue #2793: migrate_cleanup_swap_v3 MUST be wired into the pallet +// on_runtime_upgrade hook. Seeds a *Provided residual, runs the full upgrade hook, and asserts +// the residual is folded into the main reserves. Without the wiring line in hooks.rs this fails +// (the residual is never folded), which is exactly the regression the issue reports. +#[test] +fn test_migrate_cleanup_swap_v3_runs_on_runtime_upgrade() { + use crate::migrations::migrate_cleanup_swap_v3::deprecated_swap_maps; + use frame_support::traits::Hooks; + + new_test_ext(1).execute_with(|| { + let netuid = NetUid::from(1); + let provided: u64 = 9876; + + // Seed residuals that the wired migration must fold into the main reserves at upgrade. + deprecated_swap_maps::SubnetTaoProvided::::insert(netuid, TaoBalance::from(provided)); + deprecated_swap_maps::SubnetAlphaInProvided::::insert( + netuid, + AlphaBalance::from(provided), + ); + + let tao_before = u64::from(SubnetTAO::::get(netuid)); + let alpha_before = u64::from(SubnetAlphaIn::::get(netuid)); + + // Drive the real upgrade path. cleanup_swap_v3 is the last migration in the chain. + let _ = as Hooks>::on_runtime_upgrade(); + + // The wired migration folded the residual into the main reserves and cleared the maps. + assert!(!deprecated_swap_maps::SubnetTaoProvided::::contains_key(netuid)); + assert!(!deprecated_swap_maps::SubnetAlphaInProvided::::contains_key(netuid)); + assert_eq!( + u64::from(SubnetTAO::::get(netuid)), + tao_before + provided + ); + assert_eq!( + u64::from(SubnetAlphaIn::::get(netuid)), + alpha_before + provided + ); + }); +} + #[test] fn test_migrate_coldkey_swap_scheduled_to_announcements() { new_test_ext(1000).execute_with(|| { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 48106b0fdf..017a71a855 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -235,7 +235,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 428, + spec_version: 429, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,