Skip to content

Commit

Permalink
Merge pull request #1068 from UniqueNetwork/chore/migrate-foreign-ass…
Browse files Browse the repository at this point in the history
…et-to-v4

migrate foreign asset to v4 + fix foreign flags
  • Loading branch information
CertainLach authored Jun 6, 2024
2 parents f78f490 + 9a73a32 commit 0d52e2c
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pallets/foreign-assets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sp-std = { workspace = true }
staging-xcm = { workspace = true }
staging-xcm-executor = { workspace = true }
up-data-structs = { workspace = true }
derivative = { workspace = true }

[features]
default = ["std"]
Expand Down
275 changes: 265 additions & 10 deletions pallets/foreign-assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@

use core::ops::Deref;

use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};
use derivative::Derivative;
use frame_support::{
dispatch::DispatchResult, pallet_prelude::*, storage_alias, traits::EnsureOrigin, PalletId,
};
use frame_system::pallet_prelude::*;
use pallet_common::{
dispatch::CollectionDispatch, erc::CrossAccountId, XcmExtensions, NATIVE_FUNGIBLE_COLLECTION_ID,
Expand All @@ -38,8 +41,8 @@ use staging_xcm_executor::{
AssetsInHolding,
};
use up_data_structs::{
budget::ZeroBudget, CollectionId, CollectionMode, CollectionName, CollectionTokenPrefix,
CreateCollectionData, CreateFungibleData, CreateItemData, TokenId,
budget::ZeroBudget, CollectionFlags, CollectionId, CollectionMode, CollectionName,
CollectionTokenPrefix, CreateCollectionData, CreateFungibleData, CreateItemData, TokenId,
};

pub mod weights;
Expand All @@ -50,8 +53,44 @@ mod benchmarking;
pub use module::*;
pub use weights::WeightInfo;

/// Status of storage migration from an old XCM version to a new one.
#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub enum MigrationStatus {
V3ToV4(MigrationStatusV3ToV4),
}

/// Status of storage migration from XCMv3 to XCMv4.
#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub enum MigrationStatusV3ToV4 {
/// The migration is completed.
Done,

/// An asset is skipped during the migration
/// due to its inconsistent state.
SkippedInconsistentAssetData(staging_xcm::v3::AssetId),

/// An asset instance is skipped during the migration
/// due to its inconsistent state.
SkippedInconsistentAssetInstanceData {
asset_id: staging_xcm::v3::AssetId,
asset_instance: staging_xcm::v3::AssetInstance,
},

/// An asset is skipped during the migration
/// because it couldn't be converted to the new XCM version.
SkippedNotConvertibleAssetId(staging_xcm::v3::AssetId),

/// An asset instance is skipped during the migration
/// because it couldn't be converted to the new XCM version.
SkippedNotConvertibleAssetInstance {
asset_id: staging_xcm::v3::AssetId,
asset_instance: staging_xcm::v3::AssetInstance,
},
}

#[frame_support::pallet]
pub mod module {
use frame_support::traits::BuildGenesisConfig;
use pallet_common::CollectionIssuer;
use up_data_structs::CollectionDescription;

Expand Down Expand Up @@ -93,35 +132,37 @@ pub mod module {
}

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
/// The foreign asset registered.
ForeignAssetRegistered {
collection_id: CollectionId,
asset_id: Box<VersionedAssetId>,
},

/// The migration status.
MigrationStatus(MigrationStatus),
}

/// The corresponding collections of foreign assets.
#[pallet::storage]
#[pallet::getter(fn foreign_asset_to_collection)]
pub type ForeignAssetToCollection<T: Config> =
StorageMap<_, Twox64Concat, staging_xcm::v4::AssetId, CollectionId, OptionQuery>;
StorageMap<_, Blake2_128Concat, staging_xcm::v4::AssetId, CollectionId, OptionQuery>;

/// The corresponding foreign assets of collections.
#[pallet::storage]
#[pallet::getter(fn collection_to_foreign_asset)]
pub type CollectionToForeignAsset<T: Config> =
StorageMap<_, Twox64Concat, CollectionId, staging_xcm::v4::AssetId, OptionQuery>;
StorageMap<_, Blake2_128Concat, CollectionId, staging_xcm::v4::AssetId, OptionQuery>;

/// The correponding NFT token id of reserve NFTs
#[pallet::storage]
#[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)]
pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<
Hasher1 = Twox64Concat,
Hasher1 = Blake2_128Concat,
Key1 = CollectionId,
Hasher2 = Blake2_128Concat,
// Key2 = staging_xcm::v3::AssetInstance,
Key2 = staging_xcm::v4::AssetInstance,
Value = TokenId,
QueryKind = OptionQuery,
Expand All @@ -131,16 +172,18 @@ pub mod module {
#[pallet::storage]
#[pallet::getter(fn token_id_to_foreign_reserve_asset_instance)]
pub type TokenIdToForeignReserveAssetInstance<T: Config> = StorageDoubleMap<
Hasher1 = Twox64Concat,
Hasher1 = Blake2_128Concat,
Key1 = CollectionId,
Hasher2 = Blake2_128Concat,
Key2 = TokenId,
// Value = staging_xcm::v3::AssetInstance,
Value = staging_xcm::v4::AssetInstance,
QueryKind = OptionQuery,
>;

const STORAGE_VERSION: StorageVersion = StorageVersion::new(staging_xcm::v4::VERSION as u16);

#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);

#[pallet::call]
Expand Down Expand Up @@ -183,6 +226,10 @@ pub mod module {
token_prefix,
description,
mode: mode.into(),
flags: CollectionFlags {
foreign: true,
..Default::default()
},
..Default::default()
},
)?;
Expand All @@ -198,9 +245,217 @@ pub mod module {
Ok(())
}
}

#[pallet::genesis_config]
#[derive(Derivative)]
#[derivative(Default(bound = ""))]
pub struct GenesisConfig<T: Config>(PhantomData<T>);

#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
<Pallet<T>>::in_code_storage_version().put::<Pallet<T>>();
}
}

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_runtime_upgrade() -> Weight {
if Self::on_chain_storage_version() < staging_xcm::v4::VERSION as u16 {
let put_version_weight = T::DbWeight::get().writes(1);
let fix_foreign_flag_weight = Self::fix_foreign_flag();
let weight_v3_to_v4 = Self::migrate_v3_to_v4();

Self::in_code_storage_version().put::<Self>();

put_version_weight
.saturating_add(fix_foreign_flag_weight)
.saturating_add(weight_v3_to_v4)
} else {
Weight::zero()
}
}
}
}

mod v3_storage {
use super::*;

#[storage_alias]
pub type ForeignAssetToCollection<T: Config> =
StorageMap<Pallet<T>, Twox64Concat, staging_xcm::v3::AssetId, CollectionId, OptionQuery>;

#[storage_alias]
pub type CollectionToForeignAsset<T: Config> =
StorageMap<Pallet<T>, Twox64Concat, CollectionId, staging_xcm::v3::AssetId, OptionQuery>;

#[storage_alias]
pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<
Pallet<T>,
Twox64Concat,
CollectionId,
Blake2_128Concat,
staging_xcm::v3::AssetInstance,
TokenId,
OptionQuery,
>;

#[storage_alias]
pub type TokenIdToForeignReserveAssetInstance<T: Config> = StorageDoubleMap<
Pallet<T>,
Twox64Concat,
CollectionId,
Blake2_128Concat,
TokenId,
staging_xcm::v3::AssetInstance,
OptionQuery,
>;
}

impl<T: Config> Pallet<T> {
fn fix_foreign_flag() -> Weight {
let mut weight = Weight::zero();

for (_, collection_id) in v3_storage::ForeignAssetToCollection::<T>::iter() {
pallet_common::CollectionById::<T>::mutate(collection_id, |collection| {
if let Some(collection) = collection {
collection.flags.foreign = true;
}
});

weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1));
}

weight
}

fn migrate_v3_to_v4() -> Weight {
let event_weight = T::DbWeight::get().writes(1);
let collection_migration_weight = Self::migrate_collections();

Self::deposit_event(Event::<T>::MigrationStatus(MigrationStatus::V3ToV4(
MigrationStatusV3ToV4::Done,
)));

collection_migration_weight.saturating_add(event_weight)
}

fn migrate_collections() -> Weight {
use MigrationStatus::*;
use MigrationStatusV3ToV4::*;

let mut weight = Weight::zero();

for (fwd_asset_id, collection_id) in v3_storage::ForeignAssetToCollection::<T>::drain() {
let bwd_asset_id = v3_storage::CollectionToForeignAsset::<T>::take(collection_id);
weight = weight.saturating_add(T::DbWeight::get().reads(2));

let Some(bwd_asset_id) = bwd_asset_id else {
Self::deposit_event(Event::<T>::MigrationStatus(V3ToV4(
SkippedInconsistentAssetData(fwd_asset_id),
)));

weight = weight.saturating_add(T::DbWeight::get().writes(1));
continue;
};

if fwd_asset_id != bwd_asset_id {
Self::deposit_event(Event::<T>::MigrationStatus(V3ToV4(
SkippedInconsistentAssetData(fwd_asset_id),
)));

weight = weight.saturating_add(T::DbWeight::get().writes(1));
continue;
}

let Ok(asset_id) = staging_xcm::v4::AssetId::try_from(fwd_asset_id) else {
Self::deposit_event(Event::<T>::MigrationStatus(V3ToV4(
SkippedNotConvertibleAssetId(fwd_asset_id),
)));

weight = weight.saturating_add(T::DbWeight::get().writes(1));
continue;
};

<ForeignAssetToCollection<T>>::insert(&asset_id, collection_id);
<CollectionToForeignAsset<T>>::insert(collection_id, asset_id);
weight = weight.saturating_add(T::DbWeight::get().writes(2));

let migrate_tokens_weight = Self::migrate_tokens(&fwd_asset_id, collection_id);
weight = weight.saturating_add(migrate_tokens_weight);
}

weight
}

fn migrate_tokens(asset_id: &staging_xcm::v3::AssetId, collection_id: CollectionId) -> Weight {
use MigrationStatus::*;
use MigrationStatusV3ToV4::*;

let mut weight = Weight::zero();

for (fwd_asset_instance, token_id) in
v3_storage::ForeignReserveAssetInstanceToTokenId::<T>::drain_prefix(collection_id)
{
let bwd_asset_instance = v3_storage::TokenIdToForeignReserveAssetInstance::<T>::take(
collection_id,
token_id,
);
weight = weight.saturating_add(T::DbWeight::get().reads(2));

let Some(bwd_asset_instance) = bwd_asset_instance else {
Self::deposit_event(Event::<T>::MigrationStatus(V3ToV4(
SkippedInconsistentAssetInstanceData {
asset_id: *asset_id,
asset_instance: fwd_asset_instance,
},
)));

weight = weight.saturating_add(T::DbWeight::get().writes(1));
continue;
};

if fwd_asset_instance != bwd_asset_instance {
Self::deposit_event(Event::<T>::MigrationStatus(V3ToV4(
SkippedInconsistentAssetInstanceData {
asset_id: *asset_id,
asset_instance: fwd_asset_instance,
},
)));

weight = weight.saturating_add(T::DbWeight::get().writes(1));
continue;
}

let Ok(asset_instance) = staging_xcm::v4::AssetInstance::try_from(fwd_asset_instance)
else {
Self::deposit_event(Event::<T>::MigrationStatus(V3ToV4(
SkippedNotConvertibleAssetInstance {
asset_id: *asset_id,
asset_instance: fwd_asset_instance,
},
)));

weight = weight.saturating_add(T::DbWeight::get().writes(1));
continue;
};

<ForeignReserveAssetInstanceToTokenId<T>>::insert(
collection_id,
&asset_instance,
token_id,
);
<TokenIdToForeignReserveAssetInstance<T>>::insert(
collection_id,
token_id,
asset_instance,
);
weight = weight.saturating_add(T::DbWeight::get().writes(2));
}

weight
}

fn pallet_account() -> T::CrossAccountId {
let owner: T::AccountId = T::PalletId::get().into_account_truncating();
T::CrossAccountId::from_sub(owner)
Expand Down

0 comments on commit 0d52e2c

Please sign in to comment.