Skip to content

Commit

Permalink
Add storage migration for new domain registry fields
Browse files Browse the repository at this point in the history
  • Loading branch information
teor2345 committed Jan 20, 2025
1 parent 27ca2d0 commit 7497b5c
Show file tree
Hide file tree
Showing 3 changed files with 304 additions and 2 deletions.
3 changes: 2 additions & 1 deletion crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod tests;
pub mod block_tree;
mod bundle_storage_fund;
pub mod domain_registry;
pub mod migration_v2_to_v3;
pub mod runtime_registry;
mod staking;
mod staking_epoch;
Expand Down Expand Up @@ -161,7 +162,7 @@ pub type BlockTreeNodeFor<T> = crate::block_tree::BlockTreeNode<
>;

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);

/// The number of bundle of a particular domain to be included in the block is probabilistic
/// and based on the consensus chain slot probability and domain bundle slot probability, usually
Expand Down
299 changes: 299 additions & 0 deletions crates/pallet-domains/src/migration_v2_to_v3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
//! Migration module for pallet-domains storage version v2 to v3.
//!
//! TODO: remove this module after it has been deployed to Taurus.
use crate::{Config, Pallet};
use frame_support::migrations::VersionedMigration;
use frame_support::traits::UncheckedOnRuntimeUpgrade;
use frame_support::weights::Weight;

pub type VersionCheckedMigrateDomainsV2ToV3<T> = VersionedMigration<
2,
3,
VersionUncheckedMigrateV2ToV3<T>,
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;

pub struct VersionUncheckedMigrateV2ToV3<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV2ToV3<T> {
fn on_runtime_upgrade() -> Weight {
domain_registry_structure_migration::migrate_domain_registry_structure::<T>()
}
}

mod domain_registry_structure_migration {
use crate::domain_registry::{DomainConfig as DomainConfigV3, DomainObject as DomainObjectV3};
use crate::pallet::DomainRegistry as DomainRegistryV3;
use crate::runtime_registry::DomainRuntimeInfo as DomainRuntimeInfoV3;
use crate::{BalanceOf, BlockNumberFor, Config, Pallet, ReceiptHashFor};
use codec::{Decode, Encode};
use domain_runtime_primitives::{EVMChainId, MultiAccountId};
use frame_support::pallet_prelude::{OptionQuery, TypeInfo, Weight};
use frame_support::{storage_alias, Identity};
use scale_info::prelude::string::String;
use sp_core::Get;
use sp_domains::{
AutoIdDomainRuntimeConfig,
DomainId,
// changed in V3, but we use Into to convert to it
// DomainRuntimeConfig as DomainRuntimeConfigV3,
EvmDomainRuntimeConfig,
OperatorAllowList,
RuntimeId,
};
use sp_runtime::Vec;

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct DomainConfigV2<AccountId: Ord, Balance> {
/// A user defined name for this domain, should be a human-readable UTF-8 encoded string.
pub domain_name: String,
/// A pointer to the `RuntimeRegistry` entry for this domain.
pub runtime_id: RuntimeId,
/// The max bundle size for this domain, may not exceed the system-wide `MaxDomainBlockSize` limit.
pub max_bundle_size: u32,
/// The max bundle weight for this domain, may not exceed the system-wide `MaxDomainBlockWeight` limit.
pub max_bundle_weight: Weight,
/// The probability of successful bundle in a slot (active slots coefficient). This defines the
/// expected bundle production rate, must be `> 0` and `≤ 1`.
pub bundle_slot_probability: (u64, u64),
/// Allowed operators to operate for this domain.
pub operator_allow_list: OperatorAllowList<AccountId>,
// Initial balances for Domain.
pub initial_balances: Vec<(MultiAccountId, Balance)>,
}

/// Domain runtime specific information to create domain raw genesis.
#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Copy)]
#[allow(clippy::upper_case_acronyms)]
pub enum DomainRuntimeInfoV2 {
EVM { chain_id: EVMChainId },
AutoId,
}

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct DomainObjectV2<Number, ReceiptHash, AccountId: Ord, Balance> {
/// The address of the domain creator, used to validate updating the domain config.
pub owner_account_id: AccountId,
/// The consensus chain block number when the domain first instantiated.
pub created_at: Number,
/// The hash of the genesis execution receipt for this domain.
pub genesis_receipt_hash: ReceiptHash,
/// The domain config.
pub domain_config: DomainConfigV2<AccountId, Balance>,
/// Domain runtime specific information.
pub domain_runtime_info: DomainRuntimeInfoV2,
/// The amount of balance hold on the domain owner account
pub domain_instantiation_deposit: Balance,
}

#[storage_alias]
pub(super) type DomainRegistry<T: Config> = StorageMap<
Pallet<T>,
Identity,
DomainId,
DomainObjectV2<
BlockNumberFor<T>,
ReceiptHashFor<T>,
<T as frame_system::Config>::AccountId,
BalanceOf<T>,
>,
OptionQuery,
>;

pub(super) fn migrate_domain_registry_structure<T: Config>() -> Weight {
let mut domain_count = 0;

DomainRegistryV3::<T>::translate_values::<
DomainObjectV2<BlockNumberFor<T>, ReceiptHashFor<T>, T::AccountId, BalanceOf<T>>,
_,
>(|domain_object_v2| {
domain_count += 1;

let (domain_runtime_config, domain_runtime_info) =
match domain_object_v2.domain_runtime_info {
DomainRuntimeInfoV2::EVM { chain_id } => {
// Added in V3
let domain_runtime_config = EvmDomainRuntimeConfig::default();
(
domain_runtime_config.clone().into(),
DomainRuntimeInfoV3::Evm {
chain_id,
domain_runtime_config,
},
)
}
DomainRuntimeInfoV2::AutoId => {
// Added in V3
let domain_runtime_config = AutoIdDomainRuntimeConfig::default();
(
domain_runtime_config.clone().into(),
DomainRuntimeInfoV3::AutoId {
domain_runtime_config,
},
)
}
};

Some(DomainObjectV3 {
owner_account_id: domain_object_v2.owner_account_id,
created_at: domain_object_v2.created_at,
genesis_receipt_hash: domain_object_v2.genesis_receipt_hash,
domain_config: DomainConfigV3 {
domain_name: domain_object_v2.domain_config.domain_name,
runtime_id: domain_object_v2.domain_config.runtime_id,
max_bundle_size: domain_object_v2.domain_config.max_bundle_size,
max_bundle_weight: domain_object_v2.domain_config.max_bundle_weight,
bundle_slot_probability: domain_object_v2.domain_config.bundle_slot_probability,
operator_allow_list: domain_object_v2.domain_config.operator_allow_list,
initial_balances: domain_object_v2.domain_config.initial_balances,
// Added in V3
domain_runtime_config,
},
domain_runtime_info,
domain_instantiation_deposit: domain_object_v2.domain_instantiation_deposit,
})
});

// 1 read and 1 write per domain
T::DbWeight::get().reads_writes(domain_count, domain_count)
}
}

#[cfg(test)]
mod tests {
use super::domain_registry_structure_migration::{
migrate_domain_registry_structure, DomainConfigV2, DomainObjectV2, DomainRegistry,
DomainRuntimeInfoV2,
};
use crate::domain_registry::{DomainConfig as DomainConfigV3, DomainObject as DomainObjectV3};
use crate::pallet::DomainRegistry as DomainRegistryV3;
use crate::runtime_registry::DomainRuntimeInfo as DomainRuntimeInfoV3;
use crate::tests::{new_test_ext, Test};
use sp_domains::{
AutoIdDomainRuntimeConfig, DomainId, DomainRuntimeConfig as DomainRuntimeConfigV3,
EvmDomainRuntimeConfig, OperatorAllowList, PermissionedActionAllowedBy,
};

#[test]
fn test_domain_registry_structure_migration_evm() {
let mut ext = new_test_ext();
let domain_id: DomainId = 0.into();
let chain_id = 8u32.into();
let domain = DomainObjectV2 {
owner_account_id: 1u32.into(),
created_at: 2u32.into(),
genesis_receipt_hash: Default::default(),
domain_config: DomainConfigV2 {
domain_name: "test-evm-migrate".to_string(),
runtime_id: 3u32,
max_bundle_size: 4,
max_bundle_weight: 5.into(),
bundle_slot_probability: (6, 7),
operator_allow_list: OperatorAllowList::Anyone,
initial_balances: vec![],
},
domain_runtime_info: DomainRuntimeInfoV2::EVM { chain_id },
domain_instantiation_deposit: 9u32.into(),
};

ext.execute_with(|| DomainRegistry::<Test>::set(domain_id, Some(domain.clone())));

ext.commit_all().unwrap();

ext.execute_with(|| {
let weights = migrate_domain_registry_structure::<Test>();
assert_eq!(
weights,
<Test as frame_system::Config>::DbWeight::get().reads_writes(1, 1),
);
assert_eq!(
DomainRegistryV3::<Test>::get(domain_id),
Some(DomainObjectV3 {
owner_account_id: domain.owner_account_id,
created_at: domain.created_at,
genesis_receipt_hash: domain.genesis_receipt_hash,
domain_config: DomainConfigV3 {
domain_name: domain.domain_config.domain_name,
runtime_id: domain.domain_config.runtime_id,
max_bundle_size: domain.domain_config.max_bundle_size,
max_bundle_weight: domain.domain_config.max_bundle_weight,
bundle_slot_probability: domain.domain_config.bundle_slot_probability,
operator_allow_list: domain.domain_config.operator_allow_list,
initial_balances: domain.domain_config.initial_balances,
domain_runtime_config: DomainRuntimeConfigV3::Evm(EvmDomainRuntimeConfig {
initial_contract_creation_allow_list:
PermissionedActionAllowedBy::Anyone
}),
},
domain_runtime_info: DomainRuntimeInfoV3::Evm {
chain_id,
domain_runtime_config: EvmDomainRuntimeConfig {
initial_contract_creation_allow_list:
PermissionedActionAllowedBy::Anyone
},
},
domain_instantiation_deposit: domain.domain_instantiation_deposit,
})
);
});
}

#[test]
fn test_domain_registry_structure_migration_auto_id() {
let mut ext = new_test_ext();
let domain_id: DomainId = 10.into();
let domain = DomainObjectV2 {
owner_account_id: 11u32.into(),
created_at: 12u32.into(),
genesis_receipt_hash: Default::default(),
domain_config: DomainConfigV2 {
domain_name: "test-auto-id-migrate".to_string(),
runtime_id: 13u32,
max_bundle_size: 14,
max_bundle_weight: 15.into(),
bundle_slot_probability: (16, 17),
operator_allow_list: OperatorAllowList::Anyone,
initial_balances: vec![],
},
domain_runtime_info: DomainRuntimeInfoV2::AutoId,
domain_instantiation_deposit: 19u32.into(),
};

ext.execute_with(|| DomainRegistry::<Test>::set(domain_id, Some(domain.clone())));

ext.commit_all().unwrap();

ext.execute_with(|| {
let weights = migrate_domain_registry_structure::<Test>();
assert_eq!(
weights,
<Test as frame_system::Config>::DbWeight::get().reads_writes(1, 1),
);
assert_eq!(
DomainRegistryV3::<Test>::get(domain_id),
Some(DomainObjectV3 {
owner_account_id: domain.owner_account_id,
created_at: domain.created_at,
genesis_receipt_hash: domain.genesis_receipt_hash,
domain_config: DomainConfigV3 {
domain_name: domain.domain_config.domain_name,
runtime_id: domain.domain_config.runtime_id,
max_bundle_size: domain.domain_config.max_bundle_size,
max_bundle_weight: domain.domain_config.max_bundle_weight,
bundle_slot_probability: domain.domain_config.bundle_slot_probability,
operator_allow_list: domain.domain_config.operator_allow_list,
initial_balances: domain.domain_config.initial_balances,
domain_runtime_config: DomainRuntimeConfigV3::AutoId(
AutoIdDomainRuntimeConfig {}
),
},
domain_runtime_info: DomainRuntimeInfoV3::AutoId {
domain_runtime_config: AutoIdDomainRuntimeConfig {}
},
domain_instantiation_deposit: domain.domain_instantiation_deposit,
})
);
});
}
}
4 changes: 3 additions & 1 deletion crates/subspace-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: Cow::Borrowed("subspace"),
impl_name: Cow::Borrowed("subspace"),
authoring_version: 0,
spec_version: 2,
spec_version: 12,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 0,
Expand Down Expand Up @@ -978,6 +978,8 @@ pub type Executive = frame_executive::Executive<
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
// TODO: remove once migration has been deployed to Taurus
pallet_domains::migration_v2_to_v3::VersionCheckedMigrateDomainsV2ToV3<Runtime>,
>;

fn extract_segment_headers(ext: &UncheckedExtrinsic) -> Option<Vec<SegmentHeader>> {
Expand Down

0 comments on commit 7497b5c

Please sign in to comment.