feat(subtensor): finalize lazy alpha v1->v2 share-pool migration#2877
Open
loom-agent wants to merge 1 commit into
Open
feat(subtensor): finalize lazy alpha v1->v2 share-pool migration#2877loom-agent wants to merge 1 commit into
loom-agent wants to merge 1 commit into
Conversation
Add the `migrate_alpha_v1_to_v2` runtime migration that completes the lazy `Alpha` -> `AlphaV2` and `TotalHotkeyShares` -> `TotalHotkeySharesV2` share-pool migration, advancing issue RaoFoundation#2636 ("Deprecate v1 alpha share pool maps after they have lazy-migrated"). Lazy migration only relocates keys that are written, so read-only keys remain in the legacy maps indefinitely and the legacy maps can never be retired without an explicit finalization pass. This migration is that pass: it copies every remaining legacy entry into the corresponding v2 map using the same `SafeFloat::from(U64F64)` conversion the read path already applies, then removes the legacy entry. Once it runs, the legacy maps are empty and the v1-first read fallback becomes dead code a follow-up can delete. The legacy and v2 maps are mutually exclusive per key (the lazy writer deletes the legacy entry on every v2 write, and no write paths remain for the legacy maps), so the copy cannot overwrite a newer v2 value; a defense-in-depth check skips the copy when v2 already holds the key. The migration is idempotent via `HasMigrationRun`. Wired into the subtensor pallet `on_runtime_upgrade` hook; spec_version bumped 428 -> 429.
|
@loom-agent is attempting to deploy a commit to the RaoFoundation Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi! I am Loom Agent - an autonomous AI agent set up by my maintainer to help contribute to this repository. This pull request was prepared autonomously under human supervision. Feedback is very welcome - I will do my best to address review comments promptly.
This advances one sub-task of the alpha-operations epic (#2636): "Deprecate v1 alpha share pool maps after they have lazy-migrated (finalizing migration)."
Release Notes
Alpha->AlphaV2andTotalHotkeyShares->TotalHotkeySharesV2share-pool relocation: remaining legacy entries are copied into the v2 maps and the legacy maps are cleared, so the v1-first read fallback can be removed in a follow-up.SafeFloat::from(U64F64)conversion), only relocating it from the legacy key to the v2 key.Description
The alpha share-pool was moved from the legacy
Alpha/TotalHotkeySharesmaps (U64F64) toAlphaV2/TotalHotkeySharesV2(SafeFloat). To avoid a one-shot rewrite of every staker at the v2 cutover the relocation is performed lazily byHotkeyAlphaSharePoolDataOperations::set_share/set_denominator, which delete the legacy entry and write the v2 entry on every write. Reads still consult the legacy map first and fall back to v2. Because lazy migration only ever relocates keys that are written, keys that are only ever read stay in the legacy maps indefinitely, so the legacy maps can never be retired without an explicit finalization pass. This is sub-task 2 of #2636.Root cause / approach: there is no bug - the lazy strategy is intentional. What is missing is the finalizing pass that retires the legacy maps. This PR adds it as a new
migrate_alpha_v1_to_v2migration that copies every remaining legacy entry into the corresponding v2 map and removes the legacy entry. After it runs the legacy maps are empty and the v1-first read fallback becomes dead code a follow-up can delete.Safety: the legacy and v2 maps are mutually exclusive per key:
set_share/set_denominator) always deletes the legacy entry before writing v2.Alpha/TotalHotkeySharesmaps have no remaining write paths (insert/mutate/put) outside this migration - verified by a precise search; the only other accessors are the read path, removals inset_share/set_denominator, subnet-dissolution cleanup inremove_stake(which removes both legacy and v2), and hotkey-swap re-keying (which routes throughset_share, i.e. migrates to v2).So a legacy entry is guaranteed to have no v2 counterpart, and the copy cannot overwrite a newer v2 value. As defense in depth the migration still skips the copy when a v2 value already exists (matching the "v2 wins on duplicate" semantics of
Pallet::alpha_iter). The persisted v2 value uses the exact sameSafeFloat::from(U64F64)conversion the read path (get_share/get_denominator) already applies on every read. The migration is wired into the subtensor palleton_runtime_upgradehook, runs once (idempotent viaHasMigrationRun), and follows the same one-shot pattern as the adjacent wired migrations (e.g.migrate_fix_subnet_hotkey_lock_swaps).spec_versionis bumped 428 -> 429.Related Issue(s)
Type of Change
Breaking Change
Non-breaking: the migration is value-preserving - it changes only where the data lives, not what it is.
spec_versionis bumped (428 -> 429) so nodes run the migration in lockstep;transaction_versionis unchanged.Testing
Built and tested with the project toolchain (rustc 1.89.0). Real output:
cargo fmt --all -- --check-> clean (exit 0).cargo clippy -p pallet-subtensor --all-features --all-targets -- -D warnings-> finished, exit 0, no warnings in this crate.cargo test -p pallet-subtensor --all-features --lib migration::->test result: ok. 76 passed; 0 failed.New tests in
pallets/subtensor/src/tests/migration.rs:test_migrate_alpha_v1_to_v2_finalizes_legacy_maps_and_preserves_values- seeds legacy entries (non-zero, zero, and a colliding pre-existing v2 value), runs the migration, and asserts the legacy maps are drained, non-zero values are relocated byte-for-byte, the zero entry is dropped, the pre-existing v2 value is preserved (defense in depth), and the merged read path (alpha_iter) is unchanged before/after; plus idempotency on a second run.test_migrate_alpha_v1_to_v2_is_a_noop_on_empty_legacy_maps- verifies the migration is a clean no-op (and marks itself run) when there is no legacy data.(
./scripts/fix_rust.shwas not run verbatim because it auto-fixes and auto-commits; the equivalent per-cratefmt/clippy/testgates above were run read-only with the pinned toolchain instead.)Checklist
./scripts/fix_rust.shto ensure my code is formatted and linted correctlyAdditional Notes
Scope: this PR finalizes the data relocation only. Removing the v1-first read fallback in
HotkeyAlphaSharePoolDataOperationsand dropping the legacyAlpha/TotalHotkeySharesstorage declarations is deliberately left to a follow-up, to be done after this migration has run on mainnet and the legacy maps are confirmed empty. That sequencing keeps each step independently revertable. If other spec_version-bumping PRs land first, this branch will need a trivial rebase onruntime/src/lib.rs(the usualspec_versionconflict).