Finalize lazy alpha v1->v2 share-pool migration#2
Open
loom-agent wants to merge 1 commit into
Open
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.
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 PR is opened against the
loom-agent/subtensorfork first for your review before going upstream. It advances one sub-task of the upstream alpha-operations epic (RaoFoundation#2636).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 legacy
Alpha/TotalHotkeyShares(U64F64) toAlphaV2/TotalHotkeySharesV2(SafeFloat). To avoid a one-shot rewrite of every staker at the v2 cutover the move 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.Lazy migration only ever relocates keys that are written, so keys that are only ever read stay in the legacy maps indefinitely, and the legacy maps can never be retired without an explicit finalization pass. This PR adds that pass as a new
migrate_alpha_v1_to_v2migration: it 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. This is the "Deprecate v1 alpha share pool maps after they have lazy-migrated (finalizing migration)" sub-task of RaoFoundation#2636.Related Issue(s)
Type of Change
Non-breaking: the migration is value-preserving - it changes only where the data lives, not what it is.
Breaking Change
None. The migration is idempotent (
HasMigrationRun-guarded) and behavior-preserving.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. The only other writers are removals inset_share, subnet-dissolution cleanup inremove_stake, 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 pallet
on_runtime_upgradehook and runs once (idempotent viaHasMigrationRun).spec_versionis bumped 428 -> 429.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.cargo test -p pallet-subtensor --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.Checklist
cargo fmt/cargo clippy(the project formatter/linter) and they are cleanAdditional Notes
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.Alphamap at upgrade time, matching the established pattern inmigrate_fix_staking_hot_keys(which iterates the same map). If maintainers prefer a chunked / on-idle migration for the mainnet upgrade given map size, the migration function is self-contained and easy to convert.