Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pallets/subtensor/src/coinbase/reveal_commits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ impl<T: Config> Pallet<T> {
let reveal_epoch = cur_epoch.saturating_sub(reveal_period);

// Clean expired commits
for (epoch, _) in CRV3WeightCommitsV2::<T>::iter_prefix(netuid) {
for (epoch, _) in TimelockedWeightCommits::<T>::iter_prefix(netuid) {
if epoch < reveal_epoch {
CRV3WeightCommitsV2::<T>::remove(netuid, epoch);
TimelockedWeightCommits::<T>::remove(netuid, epoch);
}
}

Expand All @@ -57,7 +57,7 @@ impl<T: Config> Pallet<T> {
return Ok(());
}

let mut entries = CRV3WeightCommitsV2::<T>::take(netuid, reveal_epoch);
let mut entries = TimelockedWeightCommits::<T>::take(netuid, reveal_epoch);
let mut unrevealed = VecDeque::new();

// Keep popping items off the front of the queue until we successfully reveal a commit.
Expand Down Expand Up @@ -185,11 +185,11 @@ impl<T: Config> Pallet<T> {
continue;
}

Self::deposit_event(Event::CRV3WeightsRevealed(netuid, who));
Self::deposit_event(Event::TimelockedWeightsRevealed(netuid, who));
}

if !unrevealed.is_empty() {
CRV3WeightCommitsV2::<T>::insert(netuid, reveal_epoch, unrevealed);
TimelockedWeightCommits::<T>::insert(netuid, reveal_epoch, unrevealed);
}

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion pallets/subtensor/src/epoch/run_epoch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ impl<T: Config> Pallet<T> {
}

// ---------- v3 ------------------------------------------------------
for (_epoch, q) in CRV3WeightCommitsV2::<T>::iter_prefix(netuid) {
for (_epoch, q) in TimelockedWeightCommits::<T>::iter_prefix(netuid) {
for (who, cb, ..) in q.iter() {
if !Self::is_commit_expired(netuid, *cb) {
if let Some(i) = uid_of(who) {
Expand Down
19 changes: 18 additions & 1 deletion pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,23 @@ pub mod pallet {
OptionQuery,
>;
#[pallet::storage]
/// MAP (netuid, epoch) → VecDeque<(who, commit_block, ciphertext, reveal_round)>
/// Stores a queue of weight commits for an account on a given subnet.
pub type TimelockedWeightCommits<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
NetUid,
Twox64Concat,
u64, // epoch key
VecDeque<(
T::AccountId,
u64, // commit_block
BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>>,
RoundNumber,
)>,
ValueQuery,
>;
#[pallet::storage]
/// MAP (netuid, epoch) → VecDeque<(who, ciphertext, reveal_round)>
/// DEPRECATED for CRV3WeightCommitsV2
pub type CRV3WeightCommits<T: Config> = StorageDoubleMap<
Expand All @@ -1681,7 +1698,7 @@ pub mod pallet {
>;
#[pallet::storage]
/// MAP (netuid, epoch) → VecDeque<(who, commit_block, ciphertext, reveal_round)>
/// Stores a queue of v3 commits for an account on a given netuid.
/// DEPRECATED for TimelockedWeightCommits
pub type CRV3WeightCommitsV2<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
Expand Down
14 changes: 14 additions & 0 deletions pallets/subtensor/src/macros/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,5 +399,19 @@ mod events {
///
/// - **version**: The required version.
CommitRevealVersionSet(u16),

/// Timelocked weights have been successfully committed.
///
/// - **who**: The account ID of the user committing the weights.
/// - **netuid**: The network identifier.
/// - **commit_hash**: The hash representing the committed weights.
/// - **reveal_round**: The round at which weights can be revealed.
TimelockedWeightsCommitted(T::AccountId, NetUid, H256, u64),

/// Timelocked Weights have been successfully revealed.
///
/// - **netuid**: The network identifier.
/// - **who**: The account ID of the user revealing the weights.
TimelockedWeightsRevealed(NetUid, T::AccountId),
}
}
4 changes: 3 additions & 1 deletion pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ mod hooks {
// Migrate subnet symbols to fix the shift after subnet 81
.saturating_add(migrations::migrate_subnet_symbols::migrate_subnet_symbols::<T>())
// Migrate CRV3 add commit_block
.saturating_add(migrations::migrate_crv3_commits_add_block::migrate_crv3_commits_add_block::<T>());
.saturating_add(migrations::migrate_crv3_commits_add_block::migrate_crv3_commits_add_block::<T>())
//Migrate CRV3 to TimelockedCommits
.saturating_add(migrations::migrate_crv3_v2_to_timelocked::migrate_crv3_v2_to_timelocked::<T>());
weight
}

Expand Down
36 changes: 36 additions & 0 deletions pallets/subtensor/src/migrations/migrate_crv3_v2_to_timelocked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use super::*;
use frame_support::{traits::Get, weights::Weight};
use log;
use scale_info::prelude::string::String;
use sp_std::vec::Vec;

// --------------- Migration ------------------------------------------
/// Moves every (netuid, epoch) queue from `CRV3WeightCommitsV2` into
/// `TimelockedWeightCommits`. Identical key/value layout → pure move.
pub fn migrate_crv3_v2_to_timelocked<T: Config>() -> Weight {
let mig_name: Vec<u8> = b"crv3_v2_to_timelocked_v1".to_vec();
let mut total_weight = T::DbWeight::get().reads(1);

if HasMigrationRun::<T>::get(&mig_name) {
log::info!(
"Migration '{}' already executed - skipping",
String::from_utf8_lossy(&mig_name)
);
return total_weight;
}
log::info!("Running migration '{}'", String::from_utf8_lossy(&mig_name));

for (netuid, epoch, old_q) in CRV3WeightCommitsV2::<T>::drain() {
total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));
TimelockedWeightCommits::<T>::insert(netuid, epoch, old_q);
}

HasMigrationRun::<T>::insert(&mig_name, true);
total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1));

log::info!(
"Migration '{}' completed",
String::from_utf8_lossy(&mig_name)
);
total_weight
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod migrate_coldkey_swap_scheduled;
pub mod migrate_commit_reveal_v2;
pub mod migrate_create_root_network;
pub mod migrate_crv3_commits_add_block;
pub mod migrate_crv3_v2_to_timelocked;
pub mod migrate_delete_subnet_21;
pub mod migrate_delete_subnet_3;
pub mod migrate_disable_commit_reveal;
Expand Down
11 changes: 6 additions & 5 deletions pallets/subtensor/src/subnets/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ impl<T: Config> Pallet<T> {
/// 4. Rejects the call when the hotkey already has ≥ 10 unrevealed commits in
/// the current epoch.
/// 5. Appends `(hotkey, commit_block, commit, reveal_round)` to
/// `CRV3WeightCommitsV2[netuid][epoch]`.
/// 6. Emits `CRV3WeightsCommitted` with the Blake2 hash of `commit`.
/// `TimelockedWeightCommits[netuid][epoch]`.
/// 6. Emits `TimelockedWeightsCommitted` with the Blake2 hash of `commit`.
/// 7. Updates `LastUpdateForUid` so subsequent rate-limit checks include this
/// commit.
///
Expand All @@ -225,7 +225,7 @@ impl<T: Config> Pallet<T> {
/// * `TooManyUnrevealedCommits` – Caller already has 10 unrevealed commits.
///
/// # Events
/// * `CRV3WeightsCommitted(hotkey, netuid, commit_hash)` – Fired after the commit is successfully stored.
/// * `TimelockedWeightsCommitted(hotkey, netuid, commit_hash, reveal_round)` – Fired after the commit is successfully stored.
pub fn do_commit_timelocked_weights(
origin: T::RuntimeOrigin,
netuid: NetUid,
Expand Down Expand Up @@ -271,7 +271,7 @@ impl<T: Config> Pallet<T> {
false => Self::get_epoch_index(netuid, cur_block),
};

CRV3WeightCommitsV2::<T>::try_mutate(netuid, cur_epoch, |commits| -> DispatchResult {
TimelockedWeightCommits::<T>::try_mutate(netuid, cur_epoch, |commits| -> DispatchResult {
// 7. Verify that the number of unrevealed commits is within the allowed limit.

let unrevealed_commits_for_who = commits
Expand All @@ -289,10 +289,11 @@ impl<T: Config> Pallet<T> {
commits.push_back((who.clone(), cur_block, commit, reveal_round));

// 9. Emit the WeightsCommitted event
Self::deposit_event(Event::CRV3WeightsCommitted(
Self::deposit_event(Event::TimelockedWeightsCommitted(
who.clone(),
netuid,
commit_hash,
reveal_round,
));

// 10. Update the last commit block for the hotkey's UID.
Expand Down
81 changes: 81 additions & 0 deletions pallets/subtensor/src/tests/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,3 +1132,84 @@ fn test_migrate_disable_commit_reveal() {
);
});
}

#[test]
fn test_migrate_crv3_v2_to_timelocked() {
new_test_ext(1).execute_with(|| {
// ------------------------------
// 0. Constants / helpers
// ------------------------------
const MIG_NAME: &[u8] = b"crv3_v2_to_timelocked_v1";
let netuid = NetUid::from(99);
let epoch: u64 = 7;

// ------------------------------
// 1. Simulate OLD storage (4‑tuple; V2 layout)
// ------------------------------
let who: U256 = U256::from(0xdeadbeef_u64);
let commit_block: u64 = 12345;
let ciphertext: BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>> =
vec![1u8, 2, 3].try_into().unwrap();
let round: RoundNumber = 9;

let old_queue: VecDeque<_> =
VecDeque::from(vec![(who, commit_block, ciphertext.clone(), round)]);

// Insert under the deprecated alias
CRV3WeightCommitsV2::<Test>::insert(netuid, epoch, old_queue.clone());

// Sanity: entry decodes under old alias
assert_eq!(
CRV3WeightCommitsV2::<Test>::get(netuid, epoch),
old_queue,
"pre-migration: old queue should be present"
);

// Destination should be empty pre-migration
assert!(
TimelockedWeightCommits::<Test>::get(netuid, epoch).is_empty(),
"pre-migration: destination should be empty"
);

assert!(
!HasMigrationRun::<Test>::get(MIG_NAME.to_vec()),
"migration flag should be false before run"
);

// ------------------------------
// 2. Run migration
// ------------------------------
let w = crate::migrations::migrate_crv3_v2_to_timelocked::migrate_crv3_v2_to_timelocked::<
Test,
>();
assert!(!w.is_zero(), "weight must be non-zero");

// ------------------------------
// 3. Verify results
// ------------------------------
assert!(
HasMigrationRun::<Test>::get(MIG_NAME.to_vec()),
"migration flag not set"
);

// Old storage must be empty (drained)
assert!(
CRV3WeightCommitsV2::<Test>::get(netuid, epoch).is_empty(),
"old queue should have been drained"
);

// New storage must match exactly
let new_q = TimelockedWeightCommits::<Test>::get(netuid, epoch);
assert_eq!(
new_q, old_queue,
"migrated queue must exactly match the old queue"
);

// Verify the front element matches what we inserted
let (who2, commit_block2, cipher2, round2) = new_q.front().cloned().unwrap();
assert_eq!(who2, who);
assert_eq!(commit_block2, commit_block);
assert_eq!(cipher2, ciphertext);
assert_eq!(round2, round);
});
}
22 changes: 11 additions & 11 deletions pallets/subtensor/src/tests/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5303,7 +5303,7 @@ fn test_do_commit_crv3_weights_success() {

let cur_epoch =
SubtensorModule::get_epoch_index(netuid, SubtensorModule::get_current_block_as_u64());
let commits = CRV3WeightCommitsV2::<Test>::get(netuid, cur_epoch);
let commits = TimelockedWeightCommits::<Test>::get(netuid, cur_epoch);
assert_eq!(commits.len(), 1);
assert_eq!(commits[0].0, hotkey);
assert_eq!(commits[0].2, commit_data);
Expand Down Expand Up @@ -6158,7 +6158,7 @@ fn test_multiple_commits_by_same_hotkey_within_limit() {

let cur_epoch =
SubtensorModule::get_epoch_index(netuid, SubtensorModule::get_current_block_as_u64());
let commits = CRV3WeightCommitsV2::<Test>::get(netuid, cur_epoch);
let commits = TimelockedWeightCommits::<Test>::get(netuid, cur_epoch);
assert_eq!(
commits.len(),
10,
Expand Down Expand Up @@ -6192,7 +6192,7 @@ fn test_reveal_crv3_commits_removes_past_epoch_commits() {
for &epoch in &[past_epoch, reveal_epoch] {
let bounded_commit = vec![epoch as u8; 5].try_into().expect("bounded vec");

assert_ok!(CRV3WeightCommitsV2::<Test>::try_mutate(
assert_ok!(TimelockedWeightCommits::<Test>::try_mutate(
netuid,
epoch,
|q| -> DispatchResult {
Expand All @@ -6203,8 +6203,8 @@ fn test_reveal_crv3_commits_removes_past_epoch_commits() {
}

// Sanity – both epochs presently hold a commit.
assert!(!CRV3WeightCommitsV2::<Test>::get(netuid, past_epoch).is_empty());
assert!(!CRV3WeightCommitsV2::<Test>::get(netuid, reveal_epoch).is_empty());
assert!(!TimelockedWeightCommits::<Test>::get(netuid, past_epoch).is_empty());
assert!(!TimelockedWeightCommits::<Test>::get(netuid, reveal_epoch).is_empty());

// ---------------------------------------------------------------------
// Run the reveal pass WITHOUT a pulse – only expiry housekeeping runs.
Expand All @@ -6213,13 +6213,13 @@ fn test_reveal_crv3_commits_removes_past_epoch_commits() {

// past_epoch (< reveal_epoch) must be gone
assert!(
CRV3WeightCommitsV2::<Test>::get(netuid, past_epoch).is_empty(),
TimelockedWeightCommits::<Test>::get(netuid, past_epoch).is_empty(),
"expired epoch {past_epoch} should be cleared"
);

// reveal_epoch queue is *kept* because its commit could still be revealed later.
assert!(
!CRV3WeightCommitsV2::<Test>::get(netuid, reveal_epoch).is_empty(),
!TimelockedWeightCommits::<Test>::get(netuid, reveal_epoch).is_empty(),
"reveal-epoch {reveal_epoch} must be retained until commit can be revealed"
);
});
Expand Down Expand Up @@ -6895,7 +6895,7 @@ fn test_reveal_crv3_commits_retry_on_missing_pulse() {
));

// epoch in which commit was stored
let stored_epoch = CRV3WeightCommitsV2::<Test>::iter_prefix(netuid)
let stored_epoch = TimelockedWeightCommits::<Test>::iter_prefix(netuid)
.next()
.map(|(e, _)| e)
.expect("commit stored");
Expand All @@ -6909,7 +6909,7 @@ fn test_reveal_crv3_commits_retry_on_missing_pulse() {
// run *one* block inside reveal epoch without pulse → commit should stay queued
step_block(1);
assert!(
!CRV3WeightCommitsV2::<Test>::get(netuid, stored_epoch).is_empty(),
!TimelockedWeightCommits::<Test>::get(netuid, stored_epoch).is_empty(),
"commit must remain queued when pulse is missing"
);

Expand Down Expand Up @@ -6937,7 +6937,7 @@ fn test_reveal_crv3_commits_retry_on_missing_pulse() {
assert!(!weights.is_empty(), "weights must be set after pulse");

assert!(
CRV3WeightCommitsV2::<Test>::get(netuid, stored_epoch).is_empty(),
TimelockedWeightCommits::<Test>::get(netuid, stored_epoch).is_empty(),
"queue should be empty after successful reveal"
);
});
Expand Down Expand Up @@ -7080,7 +7080,7 @@ fn test_reveal_crv3_commits_legacy_payload_success() {

// commit should be gone
assert!(
CRV3WeightCommitsV2::<Test>::get(netuid, commit_epoch).is_empty(),
TimelockedWeightCommits::<Test>::get(netuid, commit_epoch).is_empty(),
"commit storage should be cleaned after reveal"
);
});
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,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: 302,
spec_version: 303,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down
Loading