diff --git a/.gitignore b/.gitignore index 313174c5ff..92456b3e3b 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ substrate.code-workspace target/ **/__pycache__/ *.snap +*.json diff --git a/Cargo.lock b/Cargo.lock index 005d519b4e..699cb508c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8857,6 +8857,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "hex-literal", "log", "pallet-balances", "pallet-multisig", diff --git a/integration-tests/ahm/src/tests.rs b/integration-tests/ahm/src/tests.rs index bf1faab098..9bd7a621bd 100644 --- a/integration-tests/ahm/src/tests.rs +++ b/integration-tests/ahm/src/tests.rs @@ -46,7 +46,7 @@ async fn account_migration_works() { let Some((mut rc, mut ah)) = load_externalities().await else { return }; let para_id = ParaId::from(1000); - // Simulate 10 relay blocks and grab the DMP messages + // Simulate relay blocks and grab the DMP messages let dmp_messages = rc.execute_with(|| { let mut dmps = Vec::new(); diff --git a/pallets/ah-migrator/src/proxy.rs b/pallets/ah-migrator/src/proxy.rs index 4579e5a178..aa5b23336e 100644 --- a/pallets/ah-migrator/src/proxy.rs +++ b/pallets/ah-migrator/src/proxy.rs @@ -51,6 +51,7 @@ impl Pallet { let Ok(proxy_type) = T::RcToProxyType::try_convert(p.proxy_type) else { // This is fine, eg. `Auction` proxy is not supported on AH log::warn!(target: LOG_TARGET, "Dropping unsupported proxy at index {} for {}", i, proxy.delegator.to_ss58check()); + // TODO unreserve deposit return None; }; @@ -89,7 +90,7 @@ impl Pallet { }); let (mut count_good, mut count_bad) = (0, 0); - log::info!(target: LOG_TARGET, "Integrating {} proxy announcements", announcements.len()); + log::info!(target: LOG_TARGET, "Unreserving deposits for {} proxy announcements", announcements.len()); for announcement in announcements { match Self::do_receive_proxy_announcement(announcement) { @@ -109,13 +110,14 @@ impl Pallet { pub fn do_receive_proxy_announcement( announcement: RcProxyAnnouncementOf, ) -> Result<(), Error> { + let before = frame_system::Account::::get(&announcement.depositor); let missing = ::Currency::unreserve( &announcement.depositor, announcement.deposit, ); if !missing.is_zero() { - log::warn!(target: LOG_TARGET, "Could not unreserve full proxy announcement deposit for {}, missing {:?}", announcement.depositor.to_ss58check(), missing); + log::warn!(target: LOG_TARGET, "Could not unreserve full proxy announcement deposit for {}, missing {:?}, before {:?}", announcement.depositor.to_ss58check(), missing, before); } Ok(()) diff --git a/pallets/rc-migrator/Cargo.toml b/pallets/rc-migrator/Cargo.toml index 3229abdc35..a57641160a 100644 --- a/pallets/rc-migrator/Cargo.toml +++ b/pallets/rc-migrator/Cargo.toml @@ -26,7 +26,7 @@ pallet-multisig = { workspace = true } polkadot-runtime-common = { workspace = true } runtime-parachains = { workspace = true } polkadot-parachain-primitives = { workspace = true } - +hex-literal = { workspace = true } xcm = { workspace = true } [features] diff --git a/pallets/rc-migrator/src/accounts.rs b/pallets/rc-migrator/src/accounts.rs index 31a7e97d44..918704410c 100644 --- a/pallets/rc-migrator/src/accounts.rs +++ b/pallets/rc-migrator/src/accounts.rs @@ -219,27 +219,11 @@ impl Pallet { } }; - let call = types::AssetHubPalletConfig::::AhmController( - types::AhMigratorCall::::ReceiveAccounts { accounts: package }, - ); - - let message = Xcm(vec![ - Instruction::UnpaidExecution { - weight_limit: WeightLimit::Unlimited, - check_origin: None, - }, - Instruction::Transact { - origin_kind: OriginKind::Superuser, - require_weight_at_most: Weight::from_all(1), // TODO - call: call.encode().into(), - }, - ]); - - if let Err(_err) = - send_xcm::(Location::new(0, [Junction::Parachain(1000)]), message.clone()) - { - return Err(Error::TODO); - }; + if !package.is_empty() { + Pallet::::send_chunked_xcm(package, |package| { + types::AhMigratorCall::::ReceiveAccounts { accounts: package } + })?; + } Ok(maybe_last_key) } @@ -402,7 +386,7 @@ impl Pallet { /// Since the `reserved` and `frozen` balances will be known on a receiving side (AH) they will /// be calculated there. pub fn get_consumer_count(_who: &T::AccountId, _info: &AccountInfoFor) -> u8 { - // TODO: check the pallets for provider references on Relay Chain. + // TODO: check the pallets for consumer references on Relay Chain. // The following pallets increase consumers and are deployed on (Polkadot, Kusama, Westend): // - `balances`: (P/K/W) @@ -427,7 +411,7 @@ impl Pallet { pub fn get_provider_count(_who: &T::AccountId, _info: &AccountInfoFor) -> u8 { // TODO: check the pallets for provider references on Relay Chain. - // The following pallets increase consumers and are deployed on (Polkadot, Kusama, Westend): + // The following pallets increase provider and are deployed on (Polkadot, Kusama, Westend): // - `crowdloan`: (P/K/W) https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/runtime/common/src/crowdloan/mod.rs#L416 // - `parachains_on_demand`: (P/K/W) https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/runtime/parachains/src/on_demand/mod.rs#L407 // - `balances`: (P/K/W) https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/balances/src/lib.rs#L1026 diff --git a/pallets/rc-migrator/src/lib.rs b/pallets/rc-migrator/src/lib.rs index e2783a608a..4b2a2c4288 100644 --- a/pallets/rc-migrator/src/lib.rs +++ b/pallets/rc-migrator/src/lib.rs @@ -88,7 +88,7 @@ pub enum MigrationStage { /// easier to swap out what stage should run next for testing. AccountsMigrationDone, MultisigMigrationInit, - MultiSigMigrationOngoing { + MultisigMigrationOngoing { /// Last migrated key of the `Multisigs` double map. last_key: Option<(AccountId, [u8; 32])>, }, @@ -158,10 +158,15 @@ pub mod pallet { } #[pallet::event] - //#[pallet::generate_deposit(pub(crate) fn deposit_event)] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { - /// TODO - TODO, + /// A stage transition has occurred. + StageTransition { + /// The old stage before the transition. + old: MigrationStage, + /// The new stage after the transition. + new: MigrationStage, + }, } /// The Relay Chain migration state. @@ -267,9 +272,9 @@ pub mod pallet { Self::transition(MigrationStage::MultisigMigrationInit); }, MigrationStage::MultisigMigrationInit => { - Self::transition(MigrationStage::MultiSigMigrationOngoing { last_key: None }); + Self::transition(MigrationStage::MultisigMigrationOngoing { last_key: None }); }, - MigrationStage::MultiSigMigrationOngoing { last_key } => { + MigrationStage::MultisigMigrationOngoing { last_key } => { let res = with_transaction_opaque_err::, Error, _>(|| { TransactionOutcome::Commit(MultisigMigrator::::migrate_many( last_key, @@ -287,7 +292,7 @@ pub mod pallet { Ok(Some(last_key)) => { // multisig migration continues with the next block // TODO publish event - Self::transition(MigrationStage::MultiSigMigrationOngoing { + Self::transition(MigrationStage::MultisigMigrationOngoing { last_key: Some(last_key), }); }, @@ -364,10 +369,67 @@ pub mod pallet { impl Pallet { /// Execute a stage transition and log it. - fn transition(new_stage: MigrationStage) { + fn transition(new: MigrationStage) { let old = RcMigrationStage::::get(); - RcMigrationStage::::put(&new_stage); - log::info!(target: LOG_TARGET, "[Block {:?}] Stage transition: {:?} -> {:?}", frame_system::Pallet::::block_number(), old, new_stage); + RcMigrationStage::::put(&new); + log::info!(target: LOG_TARGET, "[Block {:?}] Stage transition: {:?} -> {:?}", frame_system::Pallet::::block_number(), &old, &new); + Self::deposit_event(Event::StageTransition { old, new }); + } + + /// Split up the items into chunks of `MAX_MSG_SIZE` and send them as separate XCM + /// transacts. + /// + /// Will modify storage in the error path. + /// This is done to avoid exceeding the XCM message size limit. + pub fn send_chunked_xcm( + mut items: Vec, + create_call: impl Fn(Vec) -> types::AhMigratorCall, + ) -> Result<(), Error> { + const MAX_MSG_SIZE: u32 = 50_000; // Soft message size limit. Hard limit is about 64KiB + // Reverse in place so that we can use `pop` later on + items.reverse(); + + while !items.is_empty() { + let mut remaining_size: u32 = MAX_MSG_SIZE; + let mut batch = Vec::new(); + + while !items.is_empty() { + // Taking from the back as optimization is fine since we reversed + let item = items.last().unwrap(); // FAIL-CI no unwrap + let msg_size = item.encoded_size() as u32; + if msg_size > remaining_size { + break; + } + remaining_size -= msg_size; + + batch.push(items.pop().unwrap()); // FAIL-CI no unwrap + } + + log::info!(target: LOG_TARGET, "Sending batch of {} proxies", batch.len()); + let call = types::AssetHubPalletConfig::::AhmController(create_call(batch)); + + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + Instruction::Transact { + origin_kind: OriginKind::Superuser, + require_weight_at_most: Weight::from_all(1), // TODO + call: call.encode().into(), + }, + ]); + + if let Err(err) = send_xcm::( + Location::new(0, [Junction::Parachain(1000)]), + message.clone(), + ) { + log::error!(target: LOG_TARGET, "Error while sending XCM message: {:?}", err); + return Err(Error::TODO); + }; + } + + Ok(()) } } } diff --git a/pallets/rc-migrator/src/multisig.md b/pallets/rc-migrator/src/multisig.md index 7400d84ee0..fc5969ca6b 100644 --- a/pallets/rc-migrator/src/multisig.md +++ b/pallets/rc-migrator/src/multisig.md @@ -21,3 +21,7 @@ change the existing one. Both probably not worth it for us now. The only thing that we should do is to unlock the deposits on the AH since they were migrated to AH with the account state. + +## TODO +- Think about what if one of the multisig members' accounts are inaccessible? Like they lost their key or something. Will this impact the possibility of the remaining multisig members to re-create the same multisig on AH? + - I think it does not impact it, as the [as_multi call](https://github.com/paritytech/polkadot-sdk/blob/9cdd1178f9e8da9f08a334a8cbbda435d1ffd9dd/substrate/frame/multisig/src/lib.rs#L358-L361) just accepts Account IDs as input that do not need to be accessible. \ No newline at end of file diff --git a/pallets/rc-migrator/src/multisig.rs b/pallets/rc-migrator/src/multisig.rs index cbadb12067..b22c129ef2 100644 --- a/pallets/rc-migrator/src/multisig.rs +++ b/pallets/rc-migrator/src/multisig.rs @@ -150,7 +150,9 @@ impl PalletMigration for MultisigMigrator { } if !batch.is_empty() { - Self::send_batch_xcm(batch)?; + Pallet::::send_chunked_xcm(batch, |batch| { + types::AhMigratorCall::::ReceiveMultisigs { multisigs: batch } + })?; } Ok(last_key) @@ -170,31 +172,4 @@ impl MultisigMigrator { Ok(RcMultisig { creator: ms.depositor, deposit: ms.deposit, details: Some(k1) }) } - - /// Storage changes must be rolled back on error. - fn send_batch_xcm(multisigs: Vec>) -> Result<(), Error> { - let call = types::AssetHubPalletConfig::::AhmController( - types::AhMigratorCall::::ReceiveMultisigs { multisigs }, - ); - - let message = Xcm(vec![ - Instruction::UnpaidExecution { - weight_limit: WeightLimit::Unlimited, - check_origin: None, - }, - Instruction::Transact { - origin_kind: OriginKind::Superuser, - require_weight_at_most: Weight::from_all(1), // TODO - call: call.encode().into(), - }, - ]); - - if let Err(_err) = - send_xcm::(Location::new(0, [Junction::Parachain(1000)]), message.clone()) - { - return Err(Error::TODO); - }; - - Ok(()) - } } diff --git a/pallets/rc-migrator/src/preimage.md b/pallets/rc-migrator/src/preimage.md new file mode 100644 index 0000000000..2e3ef4df41 --- /dev/null +++ b/pallets/rc-migrator/src/preimage.md @@ -0,0 +1,193 @@ +The preimage pallet consists of three storage maps, one of which is a legacy item. The interesting one are `RequestStatusFor` and `PreimageFor`. + +## Storage: PreimageFor + +[Maps](https://github.com/paritytech/polkadot-sdk/blob/00946b10ab18331f959f5cbced7c433b6132b1cb/substrate/frame/preimage/src/lib.rs#L185) a hash and the length of a preimage to its preimage data. Preimages can be migrated rather easily by sending them in chunks from the Relay and appending them on the Asset Hub. The preimages are often used to store large governance calls. + +Q: One question here would be whether or not we want to translate these calls. I think we can and should. But I am not sure about the best time point to do so. +We can translate the preimages calls upon arrival on the Asset Hub, although there is a small change that a preimage that was not intended to be decoded as a call would be translated. +After all, the preimage pallet is a universal data storage without any implied semantics about its content. It could therefore be better to translate the preimages once we are migrating the Referenda pallet and then only translate all preimages that occur as hash lookups in a referenda. However, since the scheduler is the only way to request a preimage, all requested preimages should probably be valid calls. But the translation still needs to happen in accord with the Referenda pallet as to not invalidate its hashes. +Basically: loop referenda -> load referenda -> load preimage of referenda -> translate preimage -> calculate new preimage hash -> update preimage with new hash -> update referenda with new hash. +One further note on the preimage translation: If the length of a preimage is increased by the translation, then we should not reconsider the deposit but keep the original deposit as to not punish users for this. The cases that the translation increases the size of a preimage past the 4MiB hard limit should be negligible. + +## Storage: RequestStatusFor + +This maps preimage hashes to [RequestStatus](https://github.com/paritytech/polkadot-sdk/blob/00946b10ab18331f959f5cbced7c433b6132b1cb/substrate/frame/preimage/src/lib.rs#L81-L89). The RequestStatus contains a consideration that will be re-considered upon import. This would unreserve funds for all users that noted preimages. Possible up to 20 DOT per preimage. +The migration of this should be straighforward this but we need to remember that it must be updated if we start translating preimage calls. + +## Storage: StatusFor + +Deprecated. Will not be migrated but funds will be unreserved. + +## User Impact + +For anyone who has registered a preimage: +- If the preimage was in the new RequestStatusFor: Some unlocked funds 😎. We cannot calculate a list of affected accounts in advance since users can still influence this. +- If the preimage was in the old StatusFor: will be removed and funds unlocked. Exhaustive list of all 166 Polkadot accounts that are affected by this and will have **UP TO** these funds unlocked (not a legally binding statement): + +- `16LKv69ct6xDzSiUjuz154vCg62dkyysektHFCeJe85xb6X`: 1256.897 DOT +- `15ynbcMgPf7HbQErRz66RDLMuBVdcWVuURhR4SLPiqa6B8jx`: 633.121 DOT +- `12jW7jTPVKWahgRvxZL8ZCKKAwzy4kbrkHhzhafNjHEJXfw9`: 633.121 DOT +- `13BD4q9RYQtxkUQLvyCksnN9Pa7sC5fGj5dcdxpojxGkoHMp`: 40.229 DOT +- `13NRkBCD7NLkppxoHpYrUQ6GcjNpZEWCeXFjXDgDctANBG9j`: 40.193 DOT +- `14VwUiNPMN2T9jGvWaSm5pwcUr5ziqLjTomRm6xUxwy3Urjm`: 40.17 DOT +- `14TBcRgp166DXvMv9ZCJbKSqanUGP6tguryPQcaBqjQp8d4m`: 40.152 DOT +- `14TBcRgp166DXvMv9ZCJbKSqanUGP6tguryPQcaBqjQp8d4m`: 40.143 DOT +- `1eK9SC7Z2QFi4es2aKQHAehcZqY7bEiprkpsT483PvVK8KE`: 40.143 DOT +- `15YLDvV6Q2NUVEFBN26kRgHyyeH1Bu91NKTwBg3xW3hEVfoj`: 40.108 DOT +- `13q3NEbcSepgVbCyN6XLQtEvyZuAEqDUPLiuX2iydaQrwDCU`: 40.107 DOT +- `14M94kYk31k2hY8MpnfNPRviJ4VcsFFjBhq7V2Fs9DzCVhXc`: 40.107 DOT +- `1316cTZeHz8HtEjaJRHu8sHbp9brtUmy2LiP74KZXgXhifry`: 40.107 DOT +- `16maYYXg9chsfsBVoiSbSWzmFveamERwShPZv3SB5hVnYTmT`: 40.107 DOT +- `12ow3eJ3vbjeNRahUUrBnc98mWeJTSQ7rJCAVqiFQDEnzbu8`: 40.107 DOT +- `13g4yRs3NbtaXyu1Uww8AXd4uvrqXyR1hPR4jejRLv8rBUyB`: 40.107 DOT +- `12rpF7eUC59kU7itRe3NpSTQJroK5YiHfn5c4bT21BZxp257`: 40.107 DOT +- `16maYYXg9chsfsBVoiSbSWzmFveamERwShPZv3SB5hVnYTmT`: 40.107 DOT +- `1fN87Fgj5BUhezFgbLiGbXTMrBVggnmYBX9anzMBky8KaJ5`: 40.107 DOT +- `14PiQ7uar36zPMgEckA7qWUahYheavRL6NHCbUCkXXRNrFSc`: 40.107 DOT +- `13SceNt2ELz3ti4rnQbY1snpYH4XE4fLFsW8ph9rpwJd6HFC`: 40.107 DOT +- `1hzs7HJ4teyvX9cwFsxCaJBSNQcPAWHixQT4fem5h66cogb`: 40.107 DOT +- `15ho9t317QDvod18gCoTNe9yoiMjTXHwVxd5RC2iWyzEEby1`: 40.107 DOT +- `13SceNt2ELz3ti4rnQbY1snpYH4XE4fLFsW8ph9rpwJd6HFC`: 40.107 DOT +- `12bMyzdtiT2V9iNJ7BzQXPmzZ4KTzqFmZPSNeBmg97mFP5F4`: 40.107 DOT +- `1QjuTEKebQ3au8bxQC6iwYSPCA2iZn3YHwX8VABCauKtwRk`: 40.107 DOT +- `15fvwi77dujPz9Mk9U792gNa2Mg5z6489DPwErwCZwu7EpLE`: 40.107 DOT +- `1WgB9o954mkQi97f36azSwDt7SfRUQuJ1kCyb7Sv1WAUcSe`: 40.107 DOT +- `14zU4FXuYU2wmi2PfXLADZW92NRYEw8nfUEvi7sqiJLafJ3A`: 40.107 DOT +- `15cfSaBcTxNr8rV59cbhdMNCRagFr3GE6B3zZRsCp4QHHKPu`: 40.107 DOT +- `133VgJJgp1s9wxLqgCFxYx6T873hZQNchJM9tmbU6NkYaaqW`: 40.107 DOT +- `13YMTEPKAxPRiyaZdMKrozeNT9x1Pa5h7aExebCdi6nc3Qqd`: 40.107 DOT +- `14M94kYk31k2hY8MpnfNPRviJ4VcsFFjBhq7V2Fs9DzCVhXc`: 40.107 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.107 DOT +- `15cfSaBcTxNr8rV59cbhdMNCRagFr3GE6B3zZRsCp4QHHKPu`: 40.107 DOT +- `15qz4ZLeyXp1i4Jbx7AXiUQVCCLWVXu3dLjcTPHY3v9KGAvL`: 40.107 DOT +- `14TBcRgp166DXvMv9ZCJbKSqanUGP6tguryPQcaBqjQp8d4m`: 40.107 DOT +- `13zTcqasJT4DnDgNjmsceACcuSjt4q2geEjtMprnGXCnuuh1`: 40.107 DOT +- `12eWtdVxQ9ScYD9AzyMuSsX8B9iEikWtUGiirJ1YJtDCCuwu`: 40.107 DOT +- `1342Xpqiwwmxnhugnp91d21xR7s8V6uxXQJ1xYBQfUwbvgDB`: 40.107 DOT +- `16JA2pWJ7rXhKAq9xaCpSvVgWf6MaPLYvtSVpj7ZWjTkhYoB`: 40.107 DOT +- `1j5YyEGdcPd9BxkzVNNjKkqdi5f7g3Dd7JMgaGUhsMrZ6dZ`: 40.107 DOT +- `1njGozmydXftj6KYFPGLPN7Qq3kgmFqxsRdF5hWJAschp1S`: 40.107 DOT +- `12pdBf9NJ2jqRHdVmtqSZMRvWQoiH81AfaACgiMuXLeySNzc`: 40.107 DOT +- `1njGozmydXftj6KYFPGLPN7Qq3kgmFqxsRdF5hWJAschp1S`: 40.107 DOT +- `16MF8p8KfktKazPiQEqTXJq1CtYuZ9aNrBShXQNRdhckctC5`: 40.107 DOT +- `197nLd2rFoesjmvTfMpkFhHde7ngKzpLaA8xsbdWyeaJwzx`: 40.107 DOT +- `12BYYgmRb5BjHjZf7nykJDB1C6FXTfqr9QSmrav8RHt19ahj`: 40.107 DOT +- `12BJTP99gUerdvBhPobiTvrWwRaj1i5eFHN9qx51JWgrBtmv`: 40.107 DOT +- `1333zsMafds2sKAr8nG3zwXTCHPYv2Nm6CRgakpu6YVGt7nM`: 40.107 DOT +- `15qz4ZLeyXp1i4Jbx7AXiUQVCCLWVXu3dLjcTPHY3v9KGAvL`: 40.107 DOT +- `13EDmaUe89xXocPppFmuoAZaCsckaJy3deAyVyiykk1zKQbF`: 40.107 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.107 DOT +- `1ZVYsze5Ls3osofU6wWSp5dphr62Rj7YiL4NsXiZU3a298F`: 40.107 DOT +- `14j9cWtbvYid754crk6ieQABGYHtGZozzeavT1jc11bt32ZM`: 40.107 DOT +- `14fcqMPHhCtwnbPAHxjsf3JiGsDuLQPGMpndrWawuiAiiCqE`: 40.107 DOT +- `12dt664RtnYbeiR1D45CUPyHk1Ufv1NEHFXkuRLy47FktR31`: 40.107 DOT +- `131JKfT9kNvKjp5NJY2jHZmb32wjbr6xDHuCt4zHapWVtDde`: 40.107 DOT +- `15cfSaBcTxNr8rV59cbhdMNCRagFr3GE6B3zZRsCp4QHHKPu`: 40.107 DOT +- `1f1wZcBaJrPHkBkzx2S7KXFbjtT7KMg7fDaV47P6157KRWo`: 40.107 DOT +- `14Q5M6LWDVCPm47sVvz6M6YAEsEi5u3Rszh8z5eC2bhL9Upk`: 40.107 DOT +- `1k5ddMCPuLbu9Hax12EdKRmPwGigUKQW1ab6tRAWPxKygRF`: 40.107 DOT +- `15YLDvV6Q2NUVEFBN26kRgHyyeH1Bu91NKTwBg3xW3hEVfoj`: 40.107 DOT +- `14fhPR28n9EHZitNyf6wjYZVBPwKgcgogVjJPTzvCcb8qi9G`: 40.107 DOT +- `1RYjrCKUmvM8D9QDKCNbWJYUe49h6ZfkgXvEAtkHgvzxbGB`: 40.107 DOT +- `15wznkm7fMaJLFaw7B8KrJWkNcWsDziyTKVjrpPhRLMyXsr5`: 40.107 DOT +- `14PiQ7uar36zPMgEckA7qWUahYheavRL6NHCbUCkXXRNrFSc`: 40.107 DOT +- `14cFTN4jFFiiL1qszmGKZjokAdNr4YSD7Gf5rhZRA62TrtMb`: 40.107 DOT +- `12bqgqerfH21x5hv85AJ9AiNFWXVmBLDoCvmz78MD4fgEP7Y`: 40.107 DOT +- `15oXzySe6tjF2MumHfUodH8pFQWjy2hraRmXUJXXMKKY6p3F`: 40.107 DOT +- `1ZVYsze5Ls3osofU6wWSp5dphr62Rj7YiL4NsXiZU3a298F`: 40.107 DOT +- `12NCX9ZK1z9fxBfRraD6L4V86EmPipSerHnPcsj1k4hSkszg`: 40.107 DOT +- `126X27SbhrV19mBFawys3ovkyBS87SGfYwtwa8J2FjHrtbmA`: 40.106 DOT +- `15DL1EU6TpGDvL8HCNNU2ZDZdbcDUPiHYr1DBHBerUWMkJnT`: 40.106 DOT +- `1bqBkjrbVc6nFbpZ2oqnbEKAs99CYSf2XVAwtGVWBRxDvNY`: 40.106 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.106 DOT +- `152wswWPnwr1uLxqyENaesqjFtJcMwLT3dmrpb7KNt1PZ1PX`: 40.106 DOT +- `14M94kYk31k2hY8MpnfNPRviJ4VcsFFjBhq7V2Fs9DzCVhXc`: 40.106 DOT +- `16kkgkzjyJZL91WaL6GAUJnTZjiaowZcFyHAs5GWCNVqJimJ`: 40.106 DOT +- `14mZVYo7jy13aHTiNMQZJzsii5CPsVEaMQwLXTEMLzkmxKH2`: 40.106 DOT +- `13uvpozMRF7PCGbgPutm852Jt58nNBVUPdMFEQg5m7d1w8J8`: 40.106 DOT +- `15cfSaBcTxNr8rV59cbhdMNCRagFr3GE6B3zZRsCp4QHHKPu`: 40.106 DOT +- `123jNGxHk9ZV7oVVhFWFtMghNpmnmmTWxSpNxf8TTKzmCSQ2`: 40.106 DOT +- `16MJX8HEwhbJwN9LCKLymW812eD9N97c5EkRNVjWzhFTwhBN`: 40.106 DOT +- `13uvpozMRF7PCGbgPutm852Jt58nNBVUPdMFEQg5m7d1w8J8`: 40.106 DOT +- `14mg5GK7RoiafH7djdKgZKxKewuhj8ds19bqjioaEHR6WhQ4`: 40.106 DOT +- `1pzhyYR9gLk3GmwRtQESLkJCUXazFsAESgcbTRLc9q9hNuy`: 40.106 DOT +- `16ZhiPmAt65atW7uvNSqyK1qitQL4FQUvYz8yYXfV1EGwVP1`: 40.106 DOT +- `15kgSF6oSMFeaN7xYAykihoyQFZLRu1cF5FaBdiSDHJ233H5`: 40.106 DOT +- `1L3j12S8rmd5GvJsxzBQzFKypYX5yV2kLrPJhacUYVrLvus`: 40.106 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.106 DOT +- `13mEX6UD8t4L8YfsUxE8QjYFDkfEkAg2QpKWqKEfg5gZw3et`: 40.106 DOT +- `13uvpozMRF7PCGbgPutm852Jt58nNBVUPdMFEQg5m7d1w8J8`: 40.106 DOT +- `16Q4cR5vHLkoNqtqCZcdeKnZhY9a8AiXZAtemRJmMCpeiu82`: 40.106 DOT +- `133uT5bf5xz8xMkCmwVBWpeHjN4NyfvfqwdpXu2oZnn29kEG`: 40.106 DOT +- `13mm8mjuALSbyvfjfso22eexuFwL4MqMrcw1w5To9L52yb5h`: 40.106 DOT +- `16kkgkzjyJZL91WaL6GAUJnTZjiaowZcFyHAs5GWCNVqJimJ`: 40.106 DOT +- `12mRyiCp9zdh1wEVW5gLLiFBxDPKks72rRXmSupyEK3VAMLf`: 40.106 DOT +- `12mRyiCp9zdh1wEVW5gLLiFBxDPKks72rRXmSupyEK3VAMLf`: 40.106 DOT +- `13mm8mjuALSbyvfjfso22eexuFwL4MqMrcw1w5To9L52yb5h`: 40.106 DOT +- `167vWTbKWmJhWUitgP1hGRZfaActDyZufCVu6vqUzrhQ2pS3`: 40.106 DOT +- `15V75NT7bvs9YuVF6NTJynpTCswRshzwvcqPJZoaEJsBVxHi`: 40.106 DOT +- `15VgqbuZGdwrpGjKkJMA9nE2gqLMHyQpWmE7k6dc4fQdRMXa`: 40.106 DOT +- `12eMZTAnXEsyedXmsB6jDVRnF9Mq8ZrhLefRGhxPE4JwrPAS`: 40.106 DOT +- `121k35TZKEpoQeKURnEgt2zqWsyDKxUJkTFuwpZeLoSYUe7o`: 40.106 DOT +- `14PiQ7uar36zPMgEckA7qWUahYheavRL6NHCbUCkXXRNrFSc`: 40.106 DOT +- `16ad3ehm2XsVQbQgqYPxicRB5nGinQU9zEKiCJ7ZVhRN9CyG`: 40.106 DOT +- `123LuJKS65HaBbLSdDS46ByeC7bvQwA1iUhTpmjigQAfUKpK`: 40.106 DOT +- `1316cTZeHz8HtEjaJRHu8sHbp9brtUmy2LiP74KZXgXhifry`: 40.106 DOT +- `1316cTZeHz8HtEjaJRHu8sHbp9brtUmy2LiP74KZXgXhifry`: 40.106 DOT +- `1QgMmM5QyTBVkC9cBNPVQszCTHjCBskFG1pny8zVprPSd1J`: 40.106 DOT +- `1dwxEFdaRzBF1fpZqbXz71nLhJHvPi6a8eETjPSyC3Wrvom`: 40.106 DOT +- `12wWLUd5qMzLFGqBsMnHLVFeTuYJwuo5ygMAxuSywrBX1XSF`: 40.106 DOT +- `19C7X2ayEGaHbRb7obTd7u2crJhYm6W47XpyLC2jQBGdpif`: 40.106 DOT +- `1316cTZeHz8HtEjaJRHu8sHbp9brtUmy2LiP74KZXgXhifry`: 40.106 DOT +- `14DsLzVyTUTDMm2eP3czwPbH53KgqnQRp3CJJZS9GR7yxGDP`: 40.106 DOT +- `1xgDfXcNuB94dDcKmEG8rE9x9JVoqozCBnnitkN9nAe3Nyx`: 40.106 DOT +- `16kkgkzjyJZL91WaL6GAUJnTZjiaowZcFyHAs5GWCNVqJimJ`: 40.106 DOT +- `16aQb7rHLB8UXzd2YSh56vjAELyyq8jYaj5QdAHjVjsA3ey9`: 40.106 DOT +- `14jHouxT1VbhBDw93VW8Z89p139Qgu7ECHz3zxM2CpQEDJDB`: 40.106 DOT +- `15fHj7Q7SYxqMgZ38UpjXS8cxdq77rczTP3JgY9JVi5piMPN`: 40.106 DOT +- `149FXUmHgg75z4sk2LzFDyctNLHhzf2YxGMFHT7TakkbeQ7F`: 40.106 DOT +- `12hAtDZJGt4of3m2GqZcUCVAjZPALfvPwvtUTFZPQUbdX1Ud`: 40.106 DOT +- `13GtCixw3EZARj52CVbKLrsAzyc7dmmYhDV6quS5yeVCfnh1`: 40.106 DOT +- `15ixta6FiXTBE8gXCTUNP3ahdYWcTuateHgB2czGg5EGDVMA`: 40.106 DOT +- `15kgSF6oSMFeaN7xYAykihoyQFZLRu1cF5FaBdiSDHJ233H5`: 40.106 DOT +- `13GtCixw3EZARj52CVbKLrsAzyc7dmmYhDV6quS5yeVCfnh1`: 40.106 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.106 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.106 DOT +- `139Vbu9X3h4v7NTBVSpLijAvpWUoGhYwKmeuxaSJ9kQsD2SG`: 40.106 DOT +- `128fHaGJDKeXNNjqamUTaLe5dpU41zpbBaQA6BW9VsPKpkH6`: 40.106 DOT +- `15DL1EU6TpGDvL8HCNNU2ZDZdbcDUPiHYr1DBHBerUWMkJnT`: 40.106 DOT +- `16agh1vhJ78MiJ7tjuTd9RzreMwBwTEu15x8kCDfJy1xBYUs`: 40.106 DOT +- `16kkgkzjyJZL91WaL6GAUJnTZjiaowZcFyHAs5GWCNVqJimJ`: 40.106 DOT +- `13SceNt2ELz3ti4rnQbY1snpYH4XE4fLFsW8ph9rpwJd6HFC`: 40.106 DOT +- `1zhukWzj6pTskKUhDmyCaoJLuaHp5AVMDn5uLoNXTrw2gDR`: 40.106 DOT +- `15fHj7Q7SYxqMgZ38UpjXS8cxdq77rczTP3JgY9JVi5piMPN`: 40.106 DOT +- `12mRyiCp9zdh1wEVW5gLLiFBxDPKks72rRXmSupyEK3VAMLf`: 40.106 DOT +- `13u5odFdy7uFmRLpbgtYGWeFy8rFkcD3bYfad49B81C31pwL`: 40.106 DOT +- `16fUfF5mqL3cGGL3ai1CTL45UyNVTBHcbMkmuh5Va5M2yJ5p`: 40.106 DOT +- `14mZVYo7jy13aHTiNMQZJzsii5CPsVEaMQwLXTEMLzkmxKH2`: 40.106 DOT +- `1uamkTsQk6TwVAm6FvD7optu9fDPUh7GojEc2mZHym13Kcf`: 40.106 DOT +- `14DsLzVyTUTDMm2eP3czwPbH53KgqnQRp3CJJZS9GR7yxGDP`: 40.106 DOT +- `12CHAK3YxJG5pGW6JAGp6Daj8ruRfPwCNbPM7jU8mC2zh2qD`: 40.106 DOT +- `123LuJKS65HaBbLSdDS46ByeC7bvQwA1iUhTpmjigQAfUKpK`: 40.106 DOT +- `16k8FBUzGaAScYvewFB9g6WGt8Zms9oygPVKt7GioG4gimRp`: 40.106 DOT +- `14QQcaXERr6kzwW55L4GKmN8tC8NJRoGt1jF5D8GMWoXdyaz`: 40.106 DOT +- `13EAhGcpe93mqSFZQrQ4P2cfpdAo5txWc5UQVTfEKDoqZjhw`: 40.106 DOT +- `15SN9iNKxCJJjQ5f6JXEDxiaS6bRHxxTZtsfm3wCSSjyoENg`: 40.106 DOT +- `12mRyiCp9zdh1wEVW5gLLiFBxDPKks72rRXmSupyEK3VAMLf`: 40.106 DOT +- `15SN9iNKxCJJjQ5f6JXEDxiaS6bRHxxTZtsfm3wCSSjyoENg`: 40.106 DOT +- `15oXuEfGte2HPoxxWwz18er7LNFuLNEdXtNNk53dggkfFgCR`: 40.106 DOT +- `16agh1vhJ78MiJ7tjuTd9RzreMwBwTEu15x8kCDfJy1xBYUs`: 40.106 DOT +- `1EpEiYpWRAWmte4oPLtR5B1TZFxcBShBdjK4X9wWnq2KfLK`: 40.101 DOT +- `13Ghf2T883ZobjngC1BAgR1BWvK2P7qP37gGxHDVFf3fjbmw`: 40.1 DOT +- `13SceNt2ELz3ti4rnQbY1snpYH4XE4fLFsW8ph9rpwJd6HFC`: 40.099 DOT +- `14DsLzVyTUTDMm2eP3czwPbH53KgqnQRp3CJJZS9GR7yxGDP`: 40.087 DOT +- `1481qDmGELXNaeDi3jsLqHUSXLpSkaEg3euUX8Ya3SPoDLmt`: 40.075 DOT +- `16Drp38QW5UXWMHT7n5d5mPPH1u5Qavuv6aYAhbHfN3nzToe`: 40.074 DOT +- `14onpjYNgzDZwY57Y3w5cwwnFyp6K62mNNbgq4Xhw7zNG9iX`: 40.07 DOT +- `15nKYvAm8Yu9QVK65JWrhfyabhHkWywg21X9gX4GFJo3v4cT`: 40.069 DOT +- `138MRRCFovYvetAhv37SnNsZoCVyghYoUArhBzMzKFfFGeMP`: 40.067 DOT +- `13u5odFdy7uFmRLpbgtYGWeFy8rFkcD3bYfad49B81C31pwL`: 40.067 DOT +- `12NGmpotx1WxkZ6RrqZeMBerBUB2aa2fBCrhSPvbAJWAcF33`: 40.067 DOT +- `1EpEiYpWRAWmte4oPLtR5B1TZFxcBShBdjK4X9wWnq2KfLK`: 40.067 DOT +- `13YMTEPKAxPRiyaZdMKrozeNT9x1Pa5h7aExebCdi6nc3Qqd`: 40.067 DOT diff --git a/pallets/rc-migrator/src/proxy.md b/pallets/rc-migrator/src/proxy.md index 72b3e57cc0..d899bc4a73 100644 --- a/pallets/rc-migrator/src/proxy.md +++ b/pallets/rc-migrator/src/proxy.md @@ -3,23 +3,23 @@ The proxy pallet consists of two storage variables. ## Storage: Proxies -The [Proxies](https://github.com/paritytech/polkadot-sdk/blob/7c5224cb01710d0c14c87bf3463cc79e49b3e7b5/substrate/frame/proxy/src/lib.rs#L564-L579) storage map maps a delegator to its delegates. It can be translated one-to-one by mapping the `ProxyType` an `Delay` fields. +The [Proxies](https://github.com/paritytech/polkadot-sdk/blob/7c5224cb01710d0c14c87bf3463cc79e49b3e7b5/substrate/frame/proxy/src/lib.rs#L564-L579) storage map maps a delegator to its delegates. It can be translated one-to-one by mapping the `ProxyType` and `Delay` fields. ### Proxy Type Translation -The different kinds that are possible for a proxy are a [runtime injected type](https://github.com/paritytech/polkadot-sdk/blob/7c5224cb01710d0c14c87bf3463cc79e49b3e7b5/substrate/frame/proxy/src/lib.rs#L119-L125). Since these are different for each runtime, we need a converter that maps the Relay to AH `ProxyType` as close as possible to keep the original intention. The Relay kind is defined [here](https://github.com/polkadot-fellows/runtimes/blob/dde99603d7dbd6b8bf541d57eb30d9c07a4fce32/relay/polkadot/src/lib.rs#L1000-L1010) and the AH version [here](https://github.com/polkadot-fellows/runtimes/blob/fd8d0c23d83a7b512e721b1fde2ba3737a3478d5/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs#L453-L468). +The different kinds that are possible for a proxy are a [runtime injected type](https://github.com/paritytech/polkadot-sdk/blob/7c5224cb01710d0c14c87bf3463cc79e49b3e7b5/substrate/frame/proxy/src/lib.rs#L119-L125). Since these are different for each runtime, we need a converter that maps the Relay to AH `ProxyType` as close as possible to keep the original intention. The Relay kind is defined [here](https://github.com/polkadot-fellows/runtimes/blob/dde99603d7dbd6b8bf541d57eb30d9c07a4fce32/relay/polkadot/src/lib.rs#L1000-L1010) and the AH version [here](https://github.com/polkadot-fellows/runtimes/blob/fd8d0c23d83a7b512e721b1fde2ba3737a3478d5/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs#L453-L468). This is done by injecting a `RcToProxyType` converter into the Asset Hub migration pallet. This is not bullet proof since it relies on some copy&paste code instead of pulling in the Polkadot runtime into the AH runtime but it is the simplest solution. Mapping from Relay to AH looks as follows: - Any: same - NonTransfer: same -- Governance: needs to be added -- Staking: needs to be added +- Governance: newly added +- Staking: newly added - Variant 4: ignore as it is a historic remnant - Variant 5: ignore ditto - CancelProxy: same -- Auction: ? -- NominationPools: needs to be added +- Auction: dropped +- NominationPools: newly added -All variants that serve no purpose anymore on the Relay Chain are deleted from there. For example `Stakin`. The ones that are still usable on the relay like `NonTransfer` are **also deleted** since there is no storage deposit taken anymore. (TODO think about what is best here) -### Delay Translation +All variants that serve no purpose anymore on the Relay Chain are deleted from there. For example `Staking`. The ones that are still usable on the relay like `NonTransfer` are **also deleted** since there is no storage deposit taken anymore. (TODO think about what is best here) +### Translation of the Delay The [delay of a ProxyDefinition](https://github.com/paritytech/polkadot-sdk/blob/7c5224cb01710d0c14c87bf3463cc79e49b3e7b5/substrate/frame/proxy/src/lib.rs#L77) is measured in blocks. These are currently 6 seconds Relay blocks. To translate them to 12s AH blocks, we can divide the number by two. ## Storage: Announcements @@ -30,3 +30,8 @@ We therefore do not migrate the announcements. ## User Impact - Announcements need to be re-created - Proxies of type `Auction` are not migrated and need to be re-created on the Relay + +## TODO +- What if the owner of a proxy is lost? Then it cannot be re-created by them on the relay. + - We could do the same as the proxy replication, just in reverse; allowing anyone that can control an account ID on AH to control that same ID on the Relay. + - Otherwise we have to keep the `NonTransfer` variant alive. But then there is no deposit taken... \ No newline at end of file diff --git a/pallets/rc-migrator/src/proxy.rs b/pallets/rc-migrator/src/proxy.rs index 8ad988ddc4..0c02d49da8 100644 --- a/pallets/rc-migrator/src/proxy.rs +++ b/pallets/rc-migrator/src/proxy.rs @@ -90,9 +90,8 @@ impl PalletMigration for ProxyProxiesMigrator { let (proxies, deposit) = pallet_proxy::Proxies::::get(&acc); if proxies.is_empty() { - last_key = None; - defensive!("No more proxies to migrate"); - break; + defensive!("The proxy pallet disallows empty proxy lists"); + continue; }; match Self::migrate_single(acc.clone(), (proxies.into_inner(), deposit), weight_counter) @@ -118,7 +117,9 @@ impl PalletMigration for ProxyProxiesMigrator { // TODO send xcm if !batch.is_empty() { - Self::send_batch_xcm(batch)?; + Pallet::::send_chunked_xcm(batch, |batch| { + types::AhMigratorCall::::ReceiveProxyProxies { proxies: batch } + })?; } log::info!(target: LOG_TARGET, "Last key: {:?}", &last_key); @@ -152,55 +153,6 @@ impl ProxyProxiesMigrator { Ok(mapped) } - - /// Storage changes must be rolled back on error. - fn send_batch_xcm(mut proxies: Vec>) -> Result<(), Error> { - const MAX_MSG_SIZE: u32 = 50_000; // Soft message size limit. Hard limit is about 64KiB - - while !proxies.is_empty() { - let mut remaining_size: u32 = MAX_MSG_SIZE; - let mut batch = Vec::new(); - - while !proxies.is_empty() { - // Order does not matter, so we take from the back as optimization - let proxy = proxies.last().unwrap(); // FAIL-CI no unwrap - let msg_size = proxy.encoded_size() as u32; - if msg_size > remaining_size { - break; - } - remaining_size -= msg_size; - - batch.push(proxies.pop().unwrap()); // FAIL-CI no unwrap - } - - log::info!(target: LOG_TARGET, "Sending batch of {} proxies", batch.len()); - let call = types::AssetHubPalletConfig::::AhmController( - types::AhMigratorCall::::ReceiveProxyProxies { proxies: batch }, - ); - - let message = Xcm(vec![ - Instruction::UnpaidExecution { - weight_limit: WeightLimit::Unlimited, - check_origin: None, - }, - Instruction::Transact { - origin_kind: OriginKind::Superuser, - require_weight_at_most: Weight::from_all(1), // TODO - call: call.encode().into(), - }, - ]); - - if let Err(err) = send_xcm::( - Location::new(0, [Junction::Parachain(1000)]), - message.clone(), - ) { - log::error!(target: LOG_TARGET, "Error while sending XCM message: {:?}", err); - return Err(Error::TODO); - }; - } - - Ok(()) - } } impl PalletMigration for ProxyAnnouncementMigrator { @@ -217,11 +169,11 @@ impl PalletMigration for ProxyAnnouncementMigrator { let mut batch = Vec::new(); let mut iter = if let Some(last_key) = last_key { - pallet_proxy::Proxies::::iter_from(pallet_proxy::Proxies::::hashed_key_for( - &last_key, - )) + pallet_proxy::Announcements::::iter_from( + pallet_proxy::Announcements::::hashed_key_for(&last_key), + ) } else { - pallet_proxy::Proxies::::iter() + pallet_proxy::Announcements::::iter() }; while let Some((acc, (_announcements, deposit))) = iter.next() { @@ -233,58 +185,11 @@ impl PalletMigration for ProxyAnnouncementMigrator { } if !batch.is_empty() { - Self::send_batch_xcm(batch)?; + Pallet::::send_chunked_xcm(batch, |batch| { + types::AhMigratorCall::::ReceiveProxyAnnouncements { announcements: batch } + })?; } Ok(None) } } - -impl ProxyAnnouncementMigrator { - fn send_batch_xcm(mut announcements: Vec>) -> Result<(), Error> { - const MAX_MSG_SIZE: u32 = 50_000; // Soft message size limit. Hard limit is about 64KiB - - while !announcements.is_empty() { - let mut remaining_size: u32 = MAX_MSG_SIZE; - let mut batch = Vec::new(); - - while !announcements.is_empty() { - let announcement = announcements.last().unwrap(); // FAIL-CI no unwrap - let msg_size = announcement.encoded_size() as u32; - if msg_size > remaining_size { - break; - } - remaining_size -= msg_size; - - batch.push(announcements.pop().unwrap()); // FAIL-CI no unwrap - } - - log::info!(target: LOG_TARGET, "Sending batch of {} proxy announcements", batch.len()); - let call = types::AssetHubPalletConfig::::AhmController( - types::AhMigratorCall::::ReceiveProxyAnnouncements { announcements: batch }, - ); - - let message = Xcm(vec![ - Instruction::UnpaidExecution { - weight_limit: WeightLimit::Unlimited, - check_origin: None, - }, - Instruction::Transact { - origin_kind: OriginKind::Superuser, - require_weight_at_most: Weight::from_all(1), // TODO - call: call.encode().into(), - }, - ]); - - if let Err(err) = send_xcm::( - Location::new(0, [Junction::Parachain(1000)]), - message.clone(), - ) { - log::error!(target: LOG_TARGET, "Error while sending XCM message: {:?}", err); - return Err(Error::TODO); - }; - } - - Ok(()) - } -}