diff --git a/runtime/common/src/crowdloan/migration.rs b/runtime/common/src/crowdloan/migration.rs new file mode 100644 index 000000000000..478471454f39 --- /dev/null +++ b/runtime/common/src/crowdloan/migration.rs @@ -0,0 +1,130 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use frame_support::generate_storage_alias; + +/// Migrations for using fund index to create fund accounts instead of para ID. +pub mod crowdloan_index_migration { + use super::*; + + // The old way we generated fund accounts. + fn old_fund_account_id(index: ParaId) -> T::AccountId { + T::PalletId::get().into_sub_account(index) + } + + pub fn pre_migrate() -> Result<(), &'static str> { + // `NextTrieIndex` should have a value. + generate_storage_alias!(Crowdloan, NextTrieIndex => Value); + let next_index = NextTrieIndex::get().unwrap_or_default(); + ensure!(next_index > 0, "Next index is zero, which implies no migration is needed."); + + log::info!( + target: "runtime", + "next trie index: {:?}", + next_index, + ); + + // Each fund should have some non-zero balance. + for (para_id, fund) in Funds::::iter() { + let old_fund_account = old_fund_account_id::(para_id); + let total_balance = CurrencyOf::::total_balance(&old_fund_account); + + log::info!( + target: "runtime", + "para_id={:?}, old_fund_account={:?}, total_balance={:?}, fund.raised={:?}", + para_id, old_fund_account, total_balance, fund.raised + ); + + ensure!( + total_balance >= fund.raised, + "Total balance is not equal to the funds raised." + ); + ensure!(total_balance > Zero::zero(), "Total balance is equal to zero."); + } + + Ok(()) + } + + /// This migration converts crowdloans to use a crowdloan index rather than the parachain id as a + /// unique identifier. This makes it easier to swap two crowdloans between parachains. + pub fn migrate() -> frame_support::weights::Weight { + let mut weight = 0; + + // First migrate `NextTrieIndex` counter to `NextFundIndex`. + generate_storage_alias!(Crowdloan, NextTrieIndex => Value); + + let next_index = NextTrieIndex::take().unwrap_or_default(); + NextFundIndex::::set(next_index); + + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); + + // Migrate all accounts from `old_fund_account` to `fund_account` using `fund_index`. + for (para_id, fund) in Funds::::iter() { + let old_fund_account = old_fund_account_id::(para_id); + let new_fund_account = Pallet::::fund_account_id(fund.fund_index); + + // Funds should only have a free balance and a reserve balance. Both of these are in the + // `Account` storage item, so we just swap them. + let account_info = frame_system::Account::::take(old_fund_account); + frame_system::Account::::insert(new_fund_account, account_info); + + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); + } + + weight + } + + pub fn post_migrate() -> Result<(), &'static str> { + // `NextTrieIndex` should not have a value, and `NextFundIndex` should. + generate_storage_alias!(Crowdloan, NextTrieIndex => Value); + ensure!(NextTrieIndex::get().is_none(), "NextTrieIndex still has a value."); + + let next_index = NextFundIndex::::get(); + log::info!( + target: "runtime", + "next fund index: {:?}", + next_index, + ); + + ensure!( + next_index > 0, + "NextFundIndex was not migrated or is zero. We assume it cannot be zero else no migration is needed." + ); + + // Each fund should have balance migrated correctly. + for (para_id, fund) in Funds::::iter() { + // Old fund account is deleted. + let old_fund_account = old_fund_account_id::(para_id); + ensure!( + frame_system::Account::::get(&old_fund_account) == Default::default(), + "Old account wasn't reset to default value." + ); + + // New fund account has the correct balance. + let new_fund_account = Pallet::::fund_account_id(fund.fund_index); + let total_balance = CurrencyOf::::total_balance(&new_fund_account); + + ensure!( + total_balance >= fund.raised, + "Total balance in new account is different than the funds raised." + ); + ensure!(total_balance > Zero::zero(), "Total balance in the account is zero."); + } + + Ok(()) + } +} diff --git a/runtime/common/src/crowdloan.rs b/runtime/common/src/crowdloan/mod.rs similarity index 96% rename from runtime/common/src/crowdloan.rs rename to runtime/common/src/crowdloan/mod.rs index 84b1be08f7ef..44d45e6ec790 100644 --- a/runtime/common/src/crowdloan.rs +++ b/runtime/common/src/crowdloan/mod.rs @@ -49,6 +49,8 @@ //! the parachain remains active. Users can withdraw their funds once the slot is completed and funds are //! returned to the crowdloan account. +pub mod migration; + use crate::{ slot_range::SlotRange, traits::{Auctioneer, Registrar}, @@ -87,7 +89,7 @@ type BalanceOf = as Currency<::Acco type NegativeImbalanceOf = as Currency<::AccountId>>::NegativeImbalance; -type TrieIndex = u32; +type FundIndex = u32; pub trait WeightInfo { fn create() -> Weight; @@ -145,33 +147,33 @@ pub enum LastContribution { #[codec(dumb_trait_bound)] pub struct FundInfo { /// The owning account who placed the deposit. - depositor: AccountId, + pub depositor: AccountId, /// An optional verifier. If exists, contributions must be signed by verifier. - verifier: Option, + pub verifier: Option, /// The amount of deposit placed. - deposit: Balance, + pub deposit: Balance, /// The total amount raised. - raised: Balance, + pub raised: Balance, /// Block number after which the funding must have succeeded. If not successful at this number /// then everyone may withdraw their funds. - end: BlockNumber, + pub end: BlockNumber, /// A hard-cap on the amount that may be contributed. - cap: Balance, + pub cap: Balance, /// The most recent block that this had a contribution. Determines if we make a bid or not. /// If this is `Never`, this fund has never received a contribution. /// If this is `PreEnding(n)`, this fund received a contribution sometime in auction /// number `n` before the ending period. /// If this is `Ending(n)`, this fund received a contribution during the current ending period, /// where `n` is how far into the ending period the contribution was made. - last_contribution: LastContribution, + pub last_contribution: LastContribution, /// First lease period in range to bid on; it's actually a `LeasePeriod`, but that's the same type /// as `BlockNumber`. - first_period: LeasePeriod, + pub first_period: LeasePeriod, /// Last lease period in range to bid on; it's actually a `LeasePeriod`, but that's the same type /// as `BlockNumber`. - last_period: LeasePeriod, - /// Index used for the child trie of this fund - trie_index: TrieIndex, + pub last_period: LeasePeriod, + /// Unique index used to represent this fund. + pub fund_index: FundIndex, } #[frame_support::pallet] @@ -244,10 +246,10 @@ pub mod pallet { #[pallet::getter(fn endings_count)] pub(super) type EndingsCount = StorageValue<_, u32, ValueQuery>; - /// Tracker for the next available trie index + /// Tracker for the next available fund index #[pallet::storage] - #[pallet::getter(fn next_trie_index)] - pub(super) type NextTrieIndex = StorageValue<_, u32, ValueQuery>; + #[pallet::getter(fn next_fund_index)] + pub(super) type NextFundIndex = StorageValue<_, u32, ValueQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -342,7 +344,7 @@ pub mod pallet { // Care needs to be taken by the crowdloan creator that this function will succeed given // the crowdloaning configuration. We do some checks ahead of time in crowdloan `create`. let result = T::Auctioneer::place_bid( - Self::fund_account_id(para_id), + Self::fund_account_id(fund.fund_index), para_id, fund.first_period, fund.last_period, @@ -408,8 +410,8 @@ pub mod pallet { ensure!(depositor == manager, Error::::InvalidOrigin); ensure!(T::Registrar::is_registered(index), Error::::InvalidParaId); - let trie_index = Self::next_trie_index(); - let new_trie_index = trie_index.checked_add(1).ok_or(Error::::Overflow)?; + let fund_index = Self::next_fund_index(); + let new_fund_index = fund_index.checked_add(1).ok_or(Error::::Overflow)?; let deposit = T::SubmissionDeposit::get(); @@ -427,11 +429,11 @@ pub mod pallet { last_contribution: LastContribution::Never, first_period, last_period, - trie_index, + fund_index, }, ); - NextTrieIndex::::put(new_trie_index); + NextFundIndex::::put(new_fund_index); // Add a lock to the para so that the configuration cannot be changed. T::Registrar::apply_lock(index); @@ -479,15 +481,15 @@ pub mod pallet { let mut fund = Self::funds(index).ok_or(Error::::InvalidParaId)?; let now = frame_system::Pallet::::block_number(); - let fund_account = Self::fund_account_id(index); + let fund_account = Self::fund_account_id(fund.fund_index); Self::ensure_crowdloan_ended(now, &fund_account, &fund)?; - let (balance, _) = Self::contribution_get(fund.trie_index, &who); + let (balance, _) = Self::contribution_get(fund.fund_index, &who); ensure!(balance > Zero::zero(), Error::::NoContributions); CurrencyOf::::transfer(&fund_account, &who, balance, AllowDeath)?; - Self::contribution_kill(fund.trie_index, &who); + Self::contribution_kill(fund.fund_index, &who); fund.raised = fund.raised.saturating_sub(balance); Funds::::insert(index, &fund); @@ -510,12 +512,12 @@ pub mod pallet { let mut fund = Self::funds(index).ok_or(Error::::InvalidParaId)?; let now = frame_system::Pallet::::block_number(); - let fund_account = Self::fund_account_id(index); + let fund_account = Self::fund_account_id(fund.fund_index); Self::ensure_crowdloan_ended(now, &fund_account, &fund)?; let mut refund_count = 0u32; // Try killing the crowdloan child trie - let contributions = Self::contribution_iterator(fund.trie_index); + let contributions = Self::contribution_iterator(fund.fund_index); // Assume everyone will be refunded. let mut all_refunded = true; for (who, (balance, _)) in contributions { @@ -525,7 +527,7 @@ pub mod pallet { break } CurrencyOf::::transfer(&fund_account, &who, balance, AllowDeath)?; - Self::contribution_kill(fund.trie_index, &who); + Self::contribution_kill(fund.fund_index, &who); fund.raised = fund.raised.saturating_sub(balance); refund_count += 1; } @@ -561,7 +563,7 @@ pub mod pallet { // Assuming state is not corrupted, the child trie should already be cleaned up // and all funds in the crowdloan account have been returned. If not, governance // can take care of that. - debug_assert!(Self::contribution_iterator(fund.trie_index).count().is_zero()); + debug_assert!(Self::contribution_iterator(fund.fund_index).count().is_zero()); CurrencyOf::::unreserve(&fund.depositor, fund.deposit); Funds::::remove(index); @@ -598,7 +600,7 @@ pub mod pallet { last_contribution: fund.last_contribution, first_period, last_period, - trie_index: fund.trie_index, + fund_index: fund.fund_index, }, ); @@ -616,10 +618,10 @@ pub mod pallet { ensure!(memo.len() <= T::MaxMemoLength::get().into(), Error::::MemoTooLarge); let fund = Self::funds(index).ok_or(Error::::InvalidParaId)?; - let (balance, _) = Self::contribution_get(fund.trie_index, &who); + let (balance, _) = Self::contribution_get(fund.fund_index, &who); ensure!(balance > Zero::zero(), Error::::NoContributions); - Self::contribution_put(fund.trie_index, &who, &balance, &memo); + Self::contribution_put(fund.fund_index, &who, &balance, &memo); Self::deposit_event(Event::::MemoUpdated(who, index, memo)); Ok(()) } @@ -658,11 +660,11 @@ impl Pallet { /// /// This actually does computation. If you need to keep using it, then make sure you cache the /// value and only call this once. - pub fn fund_account_id(index: ParaId) -> T::AccountId { + pub fn fund_account_id(index: FundIndex) -> T::AccountId { T::PalletId::get().into_sub_account(index) } - pub fn id_from_index(index: TrieIndex) -> child::ChildInfo { + pub fn id_from_index(index: FundIndex) -> child::ChildInfo { let mut buf = Vec::new(); buf.extend_from_slice(b"crowdloan"); buf.extend_from_slice(&index.encode()[..]); @@ -670,7 +672,7 @@ impl Pallet { } pub fn contribution_put( - index: TrieIndex, + index: FundIndex, who: &T::AccountId, balance: &BalanceOf, memo: &[u8], @@ -678,22 +680,22 @@ impl Pallet { who.using_encoded(|b| child::put(&Self::id_from_index(index), b, &(balance, memo))); } - pub fn contribution_get(index: TrieIndex, who: &T::AccountId) -> (BalanceOf, Vec) { + pub fn contribution_get(index: FundIndex, who: &T::AccountId) -> (BalanceOf, Vec) { who.using_encoded(|b| { child::get_or_default::<(BalanceOf, Vec)>(&Self::id_from_index(index), b) }) } - pub fn contribution_kill(index: TrieIndex, who: &T::AccountId) { + pub fn contribution_kill(index: FundIndex, who: &T::AccountId) { who.using_encoded(|b| child::kill(&Self::id_from_index(index), b)); } - pub fn crowdloan_kill(index: TrieIndex) -> child::KillStorageResult { + pub fn crowdloan_kill(index: FundIndex) -> child::KillStorageResult { child::kill_storage(&Self::id_from_index(index), Some(T::RemoveKeysLimit::get())) } pub fn contribution_iterator( - index: TrieIndex, + index: FundIndex, ) -> ChildTriePrefixIterator<(T::AccountId, (BalanceOf, Vec))> { ChildTriePrefixIterator::<_>::with_prefix_over_key::( &Self::id_from_index(index), @@ -752,7 +754,7 @@ impl Pallet { ensure!(current_lease_period <= fund.first_period, Error::::ContributionPeriodOver); // Make sure crowdloan has not already won. - let fund_account = Self::fund_account_id(index); + let fund_account = Self::fund_account_id(fund.fund_index); ensure!( !T::Auctioneer::has_won_an_auction(index, &fund_account), Error::::BidOrLeaseActive @@ -762,7 +764,7 @@ impl Pallet { // contributions into the auction when it would not impact the outcome. ensure!(!T::Auctioneer::auction_status(now).is_vrf(), Error::::VrfDelayInProgress); - let (old_balance, memo) = Self::contribution_get(fund.trie_index, &who); + let (old_balance, memo) = Self::contribution_get(fund.fund_index, &who); if let Some(ref verifier) = fund.verifier { let signature = signature.ok_or(Error::::InvalidSignature)?; @@ -776,7 +778,7 @@ impl Pallet { CurrencyOf::::transfer(&who, &fund_account, value, existence)?; let balance = old_balance.saturating_add(value); - Self::contribution_put(fund.trie_index, &who, &balance, &memo); + Self::contribution_put(fund.fund_index, &who, &balance, &memo); if T::Auctioneer::auction_status(now).is_ending().is_some() { match fund.last_contribution { @@ -966,7 +968,8 @@ mod tests { // Emulate what would happen if we won an auction: // balance is reserved and a deposit_held is recorded fn set_winner(para: ParaId, who: u64, winner: bool) { - let account_id = Crowdloan::fund_account_id(para); + let fund = Funds::::get(para).unwrap(); + let account_id = Crowdloan::fund_account_id(fund.fund_index); if winner { let free_balance = Balances::free_balance(&account_id); Balances::reserve(&account_id, free_balance) @@ -1177,7 +1180,7 @@ mod tests { last_contribution: LastContribution::Never, first_period: 1, last_period: 4, - trie_index: 0, + fund_index: 0, }; assert_eq!(Crowdloan::funds(para), Some(fund_info)); // User has deposit removed from their free balance @@ -1217,7 +1220,7 @@ mod tests { last_contribution: LastContribution::Never, first_period: 1, last_period: 4, - trie_index: 0, + fund_index: 0, }; assert_eq!(Crowdloan::funds(ParaId::from(0)), Some(fund_info)); // User has deposit removed from their free balance @@ -1270,6 +1273,7 @@ mod tests { fn contribute_works() { new_test_ext().execute_with(|| { let para = new_para(); + let index = NextFundIndex::::get(); // Set up a crowdloan assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, None)); @@ -1284,7 +1288,7 @@ mod tests { // Contributions are stored in the trie assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 49); // Contributions appear in free balance of crowdloan - assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(para)), 49); + assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(index)), 49); // Crowdloan is added to NewRaise assert_eq!(Crowdloan::new_raise(), vec![para]); @@ -1300,6 +1304,7 @@ mod tests { fn contribute_with_verifier_works() { new_test_ext().execute_with(|| { let para = new_para(); + let index = NextFundIndex::::get(); let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec()); // Set up a crowdloan assert_ok!(Crowdloan::create( @@ -1364,7 +1369,7 @@ mod tests { assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 10, Some(valid_signature_2))); // Contributions appear in free balance of crowdloan - assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(para)), 59); + assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(index)), 59); // Contribution amount is correct let fund = Crowdloan::funds(para).unwrap(); @@ -1409,9 +1414,10 @@ mod tests { // If a crowdloan has already won, it should not allow contributions. let para_2 = new_para(); + let index = NextFundIndex::::get(); assert_ok!(Crowdloan::create(Origin::signed(1), para_2, 1000, 1, 4, 40, None)); // Emulate a win by leasing out and putting a deposit. Slots pallet would normally do this. - let crowdloan_account = Crowdloan::fund_account_id(para_2); + let crowdloan_account = Crowdloan::fund_account_id(index); set_winner(para_2, crowdloan_account, true); assert_noop!( Crowdloan::contribute(Origin::signed(1), para_2, 49, None), @@ -1478,6 +1484,7 @@ mod tests { fn bidding_works() { new_test_ext().execute_with(|| { let para = new_para(); + let index = NextFundIndex::::get(); let first_period = 1; let last_period = 4; @@ -1493,7 +1500,7 @@ mod tests { 9, None )); - let bidder = Crowdloan::fund_account_id(para); + let bidder = Crowdloan::fund_account_id(index); // Fund crowdloan run_to_block(1); @@ -1524,6 +1531,7 @@ mod tests { fn withdraw_from_failed_works() { new_test_ext().execute_with(|| { let para = new_para(); + let index = NextFundIndex::::get(); // Set up a crowdloan assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None)); @@ -1531,7 +1539,7 @@ mod tests { assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 50, None)); run_to_block(10); - let account_id = Crowdloan::fund_account_id(para); + let account_id = Crowdloan::fund_account_id(index); // para has no reserved funds, indicating it did not win the auction. assert_eq!(Balances::reserved_balance(&account_id), 0); // but there's still the funds in its balance. @@ -1553,13 +1561,14 @@ mod tests { fn withdraw_cannot_be_griefed() { new_test_ext().execute_with(|| { let para = new_para(); + let index = NextFundIndex::::get(); // Set up a crowdloan assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None)); assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 100, None)); run_to_block(10); - let account_id = Crowdloan::fund_account_id(para); + let account_id = Crowdloan::fund_account_id(index); // user sends the crowdloan funds trying to make an accounting error assert_ok!(Balances::transfer(Origin::signed(1), account_id, 10)); @@ -1583,7 +1592,8 @@ mod tests { fn refund_works() { new_test_ext().execute_with(|| { let para = new_para(); - let account_id = Crowdloan::fund_account_id(para); + let index = NextFundIndex::::get(); + let account_id = Crowdloan::fund_account_id(index); // Set up a crowdloan ending on 9 assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None)); @@ -1617,7 +1627,8 @@ mod tests { fn multiple_refund_works() { new_test_ext().execute_with(|| { let para = new_para(); - let account_id = Crowdloan::fund_account_id(para); + let index = NextFundIndex::::get(); + let account_id = Crowdloan::fund_account_id(index); // Set up a crowdloan ending on 9 assert_ok!(Crowdloan::create(Origin::signed(1), para, 100000, 1, 1, 9, None)); @@ -1727,7 +1738,8 @@ mod tests { fn withdraw_from_finished_works() { new_test_ext().execute_with(|| { let para = new_para(); - let account_id = Crowdloan::fund_account_id(para); + let index = NextFundIndex::::get(); + let account_id = Crowdloan::fund_account_id(index); // Set up a crowdloan assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None)); @@ -2079,7 +2091,7 @@ mod benchmarking { verify { let fund = Funds::::get(fund_index).expect("fund was created..."); assert_eq!( - Crowdloan::::contribution_get(fund.trie_index, &caller), + Crowdloan::::contribution_get(fund.fund_index, &caller), (T::MinContribution::get(), worst_memo), ); } diff --git a/runtime/common/src/integration_tests.rs b/runtime/common/src/integration_tests.rs index 370073fa4de0..7032c6badc82 100644 --- a/runtime/common/src/integration_tests.rs +++ b/runtime/common/src/integration_tests.rs @@ -20,7 +20,7 @@ use crate::{ auctions, crowdloan, paras_registrar, slot_range::SlotRange, slots, - traits::{AuctionStatus, Auctioneer, Registrar as RegistrarT}, + traits::{AuctionStatus, Auctioneer, Leaser, Registrar as RegistrarT}, }; use frame_support::{ assert_noop, assert_ok, parameter_types, @@ -29,6 +29,7 @@ use frame_support::{ }; use frame_support_test::TestRandomness; use frame_system::EnsureRoot; +use parity_scale_codec::Encode; use primitives::v1::{ BlockNumber, HeadData, Header, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, }; @@ -41,16 +42,29 @@ use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup, One}, transaction_validity::TransactionPriority, + AccountId32, }; -use sp_std::sync::Arc; +use sp_std::{convert::TryInto, sync::Arc}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; -type AccountId = u32; +type AccountId = AccountId32; type Balance = u32; type Moment = u32; +fn account_id(i: u32) -> AccountId32 { + let b4 = i.encode(); + let b32 = [&b4[..], &b4[..], &b4[..], &b4[..], &b4[..], &b4[..], &b4[..], &b4[..]].concat(); + let array: [u8; 32] = b32.try_into().unwrap(); + array.into() +} + +fn signed(i: u32) -> Origin { + let account_id = account_id(i); + Origin::signed(account_id) +} + frame_support::construct_runtime!( pub enum Test where Block = Block, @@ -342,21 +356,21 @@ fn basic_end_to_end_works() { let para_2 = LOWEST_PUBLIC_ID + 1; assert!(System::block_number().is_one()); // User 1 and 2 will own parachains - Balances::make_free_balance_be(&1, 1_000_000_000); - Balances::make_free_balance_be(&2, 1_000_000_000); + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); // First register 2 parathreads let genesis_head = Registrar::worst_head_data(); let validation_code = Registrar::worst_validation_code(); - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), ParaId::from(para_1), genesis_head.clone(), validation_code.clone(), )); - assert_ok!(Registrar::reserve(Origin::signed(2))); + assert_ok!(Registrar::reserve(signed(2))); assert_ok!(Registrar::register( - Origin::signed(2), + signed(2), ParaId::from(2001), genesis_head, validation_code, @@ -379,7 +393,7 @@ fn basic_end_to_end_works() { // Para 1 will bid directly for slot 1, 2 // Open a crowdloan for Para 2 for slot 3, 4 assert_ok!(Crowdloan::create( - Origin::signed(2), + signed(2), ParaId::from(para_2), 1_000, // Cap lease_period_index_start + 2, // First Slot @@ -387,17 +401,18 @@ fn basic_end_to_end_works() { 200 + offset, // Block End None, )); - let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(para_2)); + let fund_2 = Crowdloan::funds(ParaId::from(para_2)).unwrap(); + let crowdloan_account = Crowdloan::fund_account_id(fund_2.fund_index); // Auction ending begins on block 100 + offset, so we make a bid before then. run_to_block(90 + offset); - Balances::make_free_balance_be(&10, 1_000_000_000); - Balances::make_free_balance_be(&20, 1_000_000_000); + Balances::make_free_balance_be(&account_id(10), 1_000_000_000); + Balances::make_free_balance_be(&account_id(20), 1_000_000_000); // User 10 will bid directly for parachain 1 assert_ok!(Auctions::bid( - Origin::signed(10), + signed(10), ParaId::from(para_1), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -406,8 +421,8 @@ fn basic_end_to_end_works() { )); // User 2 will be a contribute to crowdloan for parachain 2 - Balances::make_free_balance_be(&2, 1_000_000_000); - assert_ok!(Crowdloan::contribute(Origin::signed(2), ParaId::from(para_2), 920, None)); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); + assert_ok!(Crowdloan::contribute(signed(2), ParaId::from(para_2), 920, None)); // Auction ends at block 110 + offset run_to_block(109 + offset); @@ -421,7 +436,7 @@ fn basic_end_to_end_works() { assert_eq!( slots::Leases::::get(ParaId::from(para_1)), // -- 1 --- 2 --- 3 --------- 4 ------------ 5 -------- - vec![None, None, None, Some((10, 910)), Some((10, 910))], + vec![None, None, None, Some((account_id(10), 910)), Some((account_id(10), 910))], ); assert_eq!( slots::Leases::::get(ParaId::from(para_2)), @@ -432,15 +447,15 @@ fn basic_end_to_end_works() { None, None, None, - Some((crowdloan_account, 920)), - Some((crowdloan_account, 920)) + Some((crowdloan_account.clone(), 920)), + Some((crowdloan_account.clone(), 920)) ], ); // Should not be able to contribute to a winning crowdloan - Balances::make_free_balance_be(&3, 1_000_000_000); + Balances::make_free_balance_be(&account_id(3), 1_000_000_000); assert_noop!( - Crowdloan::contribute(Origin::signed(3), ParaId::from(2001), 10, None), + Crowdloan::contribute(signed(3), ParaId::from(2001), 10, None), CrowdloanError::::BidOrLeaseActive ); @@ -508,21 +523,21 @@ fn basic_errors_fail() { assert!(System::block_number().is_one()); let para_id = LOWEST_PUBLIC_ID; // Can't double register - Balances::make_free_balance_be(&1, 1_000_000_000); - Balances::make_free_balance_be(&2, 1_000_000_000); + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); let genesis_head = Registrar::worst_head_data(); let validation_code = Registrar::worst_validation_code(); - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), para_id, genesis_head.clone(), validation_code.clone(), )); - assert_ok!(Registrar::reserve(Origin::signed(2))); + assert_ok!(Registrar::reserve(signed(2))); assert_noop!( - Registrar::register(Origin::signed(2), para_id, genesis_head, validation_code,), + Registrar::register(signed(2), para_id, genesis_head, validation_code,), paras_registrar::Error::::NotOwner ); @@ -534,7 +549,7 @@ fn basic_errors_fail() { // Cannot create a crowdloan if you do not own the para assert_noop!( Crowdloan::create( - Origin::signed(2), + signed(2), para_id, 1_000, // Cap lease_period_index_start + 2, // First Slot @@ -557,12 +572,12 @@ fn competing_slots() { // Create n paras and owners for n in 1..=max_bids { - Balances::make_free_balance_be(&n, 1_000_000_000); + Balances::make_free_balance_be(&account_id(n), 1_000_000_000); let genesis_head = Registrar::worst_head_data(); let validation_code = Registrar::worst_validation_code(); - assert_ok!(Registrar::reserve(Origin::signed(n))); + assert_ok!(Registrar::reserve(signed(n))); assert_ok!(Registrar::register( - Origin::signed(n), + signed(n), para_id + n - 1, genesis_head, validation_code, @@ -581,7 +596,7 @@ fn competing_slots() { // Increment block number run_to_block(System::block_number() + 10); - Balances::make_free_balance_be(&(n * 10), n * 1_000); + Balances::make_free_balance_be(&account_id(n * 10), n * 1_000); let (start, end) = match n { 1 => (0, 0), @@ -599,7 +614,7 @@ fn competing_slots() { // Users will bid directly for parachain assert_ok!(Auctions::bid( - Origin::signed(n * 10), + signed(n * 10), para_id + n - 1, 1, // Auction Index lease_period_index_start + start, // First Slot @@ -617,18 +632,26 @@ fn competing_slots() { assert_eq!( slots::Leases::::get(para_id), // -- 1 --- 2 --- 3 ---------- 4 ------ - vec![None, None, None, Some((10, 900))], + vec![None, None, None, Some((account_id(10), 900))], ); assert_eq!( slots::Leases::::get(para_id + 4), // -- 1 --- 2 --- 3 --- 4 ---------- 5 ------- - vec![None, None, None, None, Some((50, 4500))], + vec![None, None, None, None, Some((account_id(50), 4500))], ); // TODO: Is this right? assert_eq!( slots::Leases::::get(para_id + 8), // -- 1 --- 2 --- 3 --- 4 --- 5 ---------- 6 --------------- 7 ------- - vec![None, None, None, None, None, Some((90, 8100)), Some((90, 8100))], + vec![ + None, + None, + None, + None, + None, + Some((account_id(90), 8100)), + Some((account_id(90), 8100)) + ], ); }); } @@ -642,12 +665,12 @@ fn competing_bids() { let start_para = LOWEST_PUBLIC_ID - 1; // Create 3 paras and owners for n in 1..=3 { - Balances::make_free_balance_be(&n, 1_000_000_000); + Balances::make_free_balance_be(&account_id(n), 1_000_000_000); let genesis_head = Registrar::worst_head_data(); let validation_code = Registrar::worst_validation_code(); - assert_ok!(Registrar::reserve(Origin::signed(n))); + assert_ok!(Registrar::reserve(signed(n))); assert_ok!(Registrar::register( - Origin::signed(n), + signed(n), ParaId::from(start_para + n), genesis_head, validation_code, @@ -666,7 +689,7 @@ fn competing_bids() { for n in 1..=3 { // Create a crowdloan for each para assert_ok!(Crowdloan::create( - Origin::signed(n), + signed(n), ParaId::from(start_para + n), 100_000, // Cap lease_period_index_start + 2, // First Slot @@ -680,14 +703,14 @@ fn competing_bids() { // Increment block number run_to_block(starting_block + n * 10); - Balances::make_free_balance_be(&(n * 10), n * 1_000); + Balances::make_free_balance_be(&account_id(n * 10), n * 1_000); let para = start_para + n % 3 + 1; if n % 2 == 0 { // User 10 will bid directly for parachain 1 assert_ok!(Auctions::bid( - Origin::signed(n * 10), + signed(n * 10), ParaId::from(para), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -697,7 +720,7 @@ fn competing_bids() { } else { // User 20 will be a contribute to crowdloan for parachain 2 assert_ok!(Crowdloan::contribute( - Origin::signed(n * 10), + signed(n * 10), ParaId::from(para), n + 900, None, @@ -709,7 +732,8 @@ fn competing_bids() { run_to_block(starting_block + 110); // Appropriate Paras should have won slots - let crowdloan_2 = Crowdloan::fund_account_id(ParaId::from(2001)); + let fund_1 = Crowdloan::funds(ParaId::from(2000)).unwrap(); + let crowdloan_1 = Crowdloan::fund_account_id(fund_1.fund_index); assert_eq!( slots::Leases::::get(ParaId::from(2000)), // -- 1 --- 2 --- 3 --- 4 --- 5 ------------- 6 ------------------------ 7 ------------- @@ -719,14 +743,14 @@ fn competing_bids() { None, None, None, - Some((crowdloan_2, 1812)), - Some((crowdloan_2, 1812)) + Some((crowdloan_1.clone(), 1812)), + Some((crowdloan_1.clone(), 1812)) ], ); assert_eq!( slots::Leases::::get(ParaId::from(2002)), // -- 1 --- 2 --- 3 ---------- 4 --------------- 5 ------- - vec![None, None, None, Some((80, 7200)), Some((80, 7200))], + vec![None, None, None, Some((account_id(80), 7200)), Some((account_id(80), 7200))], ); }); } @@ -735,21 +759,21 @@ fn competing_bids() { fn basic_swap_works() { // This test will test a swap between a parachain and parathread works successfully. new_test_ext().execute_with(|| { - assert!(System::block_number().is_one()); // So events are emitted - // User 1 and 2 will own paras - Balances::make_free_balance_be(&1, 1_000_000_000); - Balances::make_free_balance_be(&2, 1_000_000_000); + assert!(System::block_number().is_one()); /* So events are emitted */ + // User 1 and 2 will own paras + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); // First register 2 parathreads with different data - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), ParaId::from(2000), test_genesis_head(10), test_validation_code(10), )); - assert_ok!(Registrar::reserve(Origin::signed(2))); + assert_ok!(Registrar::reserve(signed(2))); assert_ok!(Registrar::register( - Origin::signed(2), + signed(2), ParaId::from(2001), test_genesis_head(20), test_validation_code(20), @@ -771,7 +795,7 @@ fn basic_swap_works() { // Open a crowdloan for Para 1 for slots 0-3 assert_ok!(Crowdloan::create( - Origin::signed(1), + signed(1), ParaId::from(2000), 1_000_000, // Cap lease_period_index_start + 0, // First Slot @@ -779,13 +803,14 @@ fn basic_swap_works() { 200, // Block End None, )); - let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000)); + let fund = Crowdloan::funds(ParaId::from(2000)).unwrap(); + let crowdloan_account = Crowdloan::fund_account_id(fund.fund_index); // Bunch of contributions let mut total = 0; for i in 10..20 { - Balances::make_free_balance_be(&i, 1_000_000_000); - assert_ok!(Crowdloan::contribute(Origin::signed(i), ParaId::from(2000), 900 - i, None)); + Balances::make_free_balance_be(&account_id(i), 1_000_000_000); + assert_ok!(Crowdloan::contribute(signed(i), ParaId::from(2000), 900 - i, None)); total += 900 - i; } assert!(total > 0); @@ -796,8 +821,8 @@ fn basic_swap_works() { // Deposit is appropriately taken // ----------------------------------------- para deposit --- crowdloan - assert_eq!(Balances::reserved_balance(&1), (500 + 10 * 2 * 1) + 100); - assert_eq!(Balances::reserved_balance(&2), 500 + 20 * 2 * 1); + assert_eq!(Balances::reserved_balance(&account_id(1)), (500 + 10 * 2 * 1) + 100); + assert_eq!(Balances::reserved_balance(&account_id(2)), 500 + 20 * 2 * 1); assert_eq!(Balances::reserved_balance(&crowdloan_account), total); // Crowdloan is appropriately set assert!(Crowdloan::funds(ParaId::from(2000)).is_some()); @@ -839,8 +864,8 @@ fn basic_swap_works() { // Deregister parathread assert_ok!(Registrar::deregister(para_origin(2000).into(), ParaId::from(2000))); // Correct deposit is unreserved - assert_eq!(Balances::reserved_balance(&1), 100); // crowdloan deposit left over - assert_eq!(Balances::reserved_balance(&2), 500 + 20 * 2 * 1); + assert_eq!(Balances::reserved_balance(&account_id(1)), 100); // crowdloan deposit left over + assert_eq!(Balances::reserved_balance(&account_id(2)), 500 + 20 * 2 * 1); // Crowdloan ownership is swapped assert!(Crowdloan::funds(ParaId::from(2000)).is_none()); assert!(Crowdloan::funds(ParaId::from(2001)).is_some()); @@ -850,11 +875,11 @@ fn basic_swap_works() { // Cant dissolve assert_noop!( - Crowdloan::dissolve(Origin::signed(1), ParaId::from(2000)), + Crowdloan::dissolve(signed(1), ParaId::from(2000)), CrowdloanError::::InvalidParaId ); assert_noop!( - Crowdloan::dissolve(Origin::signed(2), ParaId::from(2001)), + Crowdloan::dissolve(signed(2), ParaId::from(2001)), CrowdloanError::::NotReadyToDissolve ); @@ -864,39 +889,198 @@ fn basic_swap_works() { // Withdraw of contributions works assert_eq!(Balances::free_balance(&crowdloan_account), total); for i in 10..20 { - assert_ok!(Crowdloan::withdraw(Origin::signed(i), i, ParaId::from(2001))); + assert_ok!(Crowdloan::withdraw(signed(i), account_id(i), ParaId::from(2001))); } assert_eq!(Balances::free_balance(&crowdloan_account), 0); // Dissolve returns the balance of the person who put a deposit for crowdloan - assert_ok!(Crowdloan::dissolve(Origin::signed(1), ParaId::from(2001))); - assert_eq!(Balances::reserved_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&2), 500 + 20 * 2 * 1); + assert_ok!(Crowdloan::dissolve(signed(1), ParaId::from(2001))); + assert_eq!(Balances::reserved_balance(&account_id(1)), 0); + assert_eq!(Balances::reserved_balance(&account_id(2)), 500 + 20 * 2 * 1); // Final deregister sets everything back to the start assert_ok!(Registrar::deregister(para_origin(2001).into(), ParaId::from(2001))); - assert_eq!(Balances::reserved_balance(&2), 0); + assert_eq!(Balances::reserved_balance(&account_id(2)), 0); + }) +} + +#[test] +fn parachain_swap_works() { + // This test will test a swap between two parachains works successfully. + new_test_ext().execute_with(|| { + assert!(System::block_number().is_one()); /* So events are emitted */ + // User 1 and 2 will own paras + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); + // First register 2 parathreads with different data + assert_ok!(Registrar::reserve(signed(1))); + assert_ok!(Registrar::register( + signed(1), + ParaId::from(2000), + test_genesis_head(10), + test_validation_code(10), + )); + assert_ok!(Registrar::reserve(signed(2))); + assert_ok!(Registrar::register( + signed(2), + ParaId::from(2001), + test_genesis_head(20), + test_validation_code(20), + )); + + // Paras should be onboarding + assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Onboarding)); + assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Onboarding)); + + assert_eq!( + Balances::total_balance(&Crowdloan::fund_account_id(Crowdloan::next_fund_index())), + 0 + ); + + // Start a new auction in the future + let start_auction = |lease_period_index_start, winner, end| { + let unique_id = winner - 1999u32; + let starting_block = System::block_number(); + let duration = 99u32; + assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start)); + + // 2 sessions later they are parathreads + run_to_block(starting_block + 20); + assert_eq!(Paras::lifecycle(ParaId::from(winner)), Some(ParaLifecycle::Parathread)); + + // Open a crowdloan for Para 1 for slots 0-3 + assert_ok!(Crowdloan::create( + signed(unique_id), + ParaId::from(winner), + 1_000_000, // Cap + lease_period_index_start + 0, // First Slot + lease_period_index_start + 7, // Last Slot + end, // Block End + None, + )); + let winner_fund = Crowdloan::funds(ParaId::from(winner)).unwrap(); + let crowdloan_account = Crowdloan::fund_account_id(winner_fund.fund_index); + + // Bunch of contributions + let mut total = 0; + for i in (unique_id * 10)..(unique_id + 1) * 10 { + Balances::make_free_balance_be(&account_id(i), 1_000_000_000); + assert_ok!(Crowdloan::contribute(signed(i), ParaId::from(winner), 900 - i, None)); + total += 900 - i; + } + assert!(total > 0); + assert_eq!(Balances::free_balance(&crowdloan_account), total); + + // Go to end of auction where everyone won their slots + run_to_block(end); + + // Crowdloan is appropriately set + assert!(Crowdloan::funds(ParaId::from(winner)).is_some()); + + // New leases will start on block lease period index * 100 + let lease_start_block = lease_period_index_start * 100; + run_to_block(lease_start_block); + }; + + start_auction(4u32, 2000, 200); + // Slots are won by Para 1 + assert!(!Slots::lease(ParaId::from(2000)).is_empty()); + assert!(Slots::lease(ParaId::from(2001)).is_empty()); + + // 2 sessions later it is a parachain + run_to_block(4 * 100 + 20); + assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parachain)); + assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parathread)); + + // Let's repeat the process now for another parachain. + start_auction(6u32, 2001, 500); + // Slots are won by Para 1 + assert!(!Slots::lease(ParaId::from(2000)).is_empty()); + assert!(!Slots::lease(ParaId::from(2001)).is_empty()); + + // 2 sessions later it is a parachain + run_to_block(6 * 100 + 20); + assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parachain)); + assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parachain)); + + // Currently we are on lease 6 + assert_eq!( + >::lease_period_index(System::block_number()), + Some((6u32, false)) + ); + + // This means that parachain 1 should only have 6 slots left, and parachain 2 has all 8. + assert_eq!(slots::Leases::::get(ParaId::from(2000)).len(), 6); + assert_eq!(slots::Leases::::get(ParaId::from(2001)).len(), 8); + + let fund_2000 = Crowdloan::funds(ParaId::from(2000)).unwrap(); + assert_eq!(fund_2000.fund_index, 0); + assert_eq!( + Balances::reserved_balance(&Crowdloan::fund_account_id(fund_2000.fund_index)), + fund_2000.raised + ); + + let fund_2001 = Crowdloan::funds(ParaId::from(2001)).unwrap(); + assert_eq!(fund_2001.fund_index, 1); + assert_eq!( + Balances::reserved_balance(&Crowdloan::fund_account_id(fund_2001.fund_index)), + fund_2001.raised + ); + + assert_eq!(Slots::lease(ParaId::from(2000)).len(), 6); + assert_eq!(Slots::lease(ParaId::from(2001)).len(), 8); + + // Now we swap them. + assert_ok!(Registrar::swap( + para_origin(2000).into(), + ParaId::from(2000), + ParaId::from(2001) + )); + assert_ok!(Registrar::swap( + para_origin(2001).into(), + ParaId::from(2001), + ParaId::from(2000) + )); + + // Crowdloan Swapped + let fund_2000 = Crowdloan::funds(ParaId::from(2000)).unwrap(); + assert_eq!(fund_2000.fund_index, 1); + assert_eq!( + Balances::reserved_balance(&Crowdloan::fund_account_id(fund_2000.fund_index)), + fund_2000.raised + ); + + let fund_2001 = Crowdloan::funds(ParaId::from(2001)).unwrap(); + assert_eq!(fund_2001.fund_index, 0); + assert_eq!( + Balances::reserved_balance(&Crowdloan::fund_account_id(fund_2001.fund_index)), + fund_2001.raised + ); + + // Slots Swapped + assert_eq!(Slots::lease(ParaId::from(2000)).len(), 8); + assert_eq!(Slots::lease(ParaId::from(2001)).len(), 6); }) } #[test] fn crowdloan_ending_period_bid() { new_test_ext().execute_with(|| { - assert!(System::block_number().is_one()); // So events are emitted - // User 1 and 2 will own paras - Balances::make_free_balance_be(&1, 1_000_000_000); - Balances::make_free_balance_be(&2, 1_000_000_000); + assert!(System::block_number().is_one()); /* So events are emitted */ + // User 1 and 2 will own paras + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); // First register 2 parathreads - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), ParaId::from(2000), test_genesis_head(10), test_validation_code(10), )); - assert_ok!(Registrar::reserve(Origin::signed(2))); + assert_ok!(Registrar::reserve(signed(2))); assert_ok!(Registrar::register( - Origin::signed(2), + signed(2), ParaId::from(2001), test_genesis_head(20), test_validation_code(20), @@ -918,7 +1102,7 @@ fn crowdloan_ending_period_bid() { // Open a crowdloan for Para 1 for slots 0-3 assert_ok!(Crowdloan::create( - Origin::signed(1), + signed(1), ParaId::from(2000), 1_000_000, // Cap lease_period_index_start + 0, // First Slot @@ -926,22 +1110,23 @@ fn crowdloan_ending_period_bid() { 200, // Block End None, )); - let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000)); + let fund = Crowdloan::funds(ParaId::from(2000)).unwrap(); + let crowdloan_account = Crowdloan::fund_account_id(fund.fund_index); // Bunch of contributions let mut total = 0; for i in 10..20 { - Balances::make_free_balance_be(&i, 1_000_000_000); - assert_ok!(Crowdloan::contribute(Origin::signed(i), ParaId::from(2000), 900 - i, None)); + Balances::make_free_balance_be(&account_id(i), 1_000_000_000); + assert_ok!(Crowdloan::contribute(signed(i), ParaId::from(2000), 900 - i, None)); total += 900 - i; } assert!(total > 0); assert_eq!(Balances::free_balance(&crowdloan_account), total); // Bid for para 2 directly - Balances::make_free_balance_be(&2, 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); assert_ok!(Auctions::bid( - Origin::signed(2), + signed(2), ParaId::from(2001), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -953,24 +1138,25 @@ fn crowdloan_ending_period_bid() { run_to_block(100); assert_eq!(Auctions::auction_status(100), AuctionStatus::::EndingPeriod(0, 0)); - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(2001), 900)); + let mut winning = [(); SlotRange::SLOT_RANGE_COUNT].map(|_| None); + + winning[SlotRange::ZeroOne as u8 as usize] = Some((account_id(2), ParaId::from(2001), 900)); winning[SlotRange::ZeroThree as u8 as usize] = - Some((crowdloan_account, ParaId::from(2000), total)); + Some((crowdloan_account.clone(), ParaId::from(2000), total)); assert_eq!(Auctions::winning(0), Some(winning)); run_to_block(101); - Balances::make_free_balance_be(&1234, 1_000_000_000); - assert_ok!(Crowdloan::contribute(Origin::signed(1234), ParaId::from(2000), 900, None)); + Balances::make_free_balance_be(&account_id(1234), 1_000_000_000); + assert_ok!(Crowdloan::contribute(signed(1234), ParaId::from(2000), 900, None)); // Data propagates correctly run_to_block(102); - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(2001), 900)); + let mut winning = [(); SlotRange::SLOT_RANGE_COUNT].map(|_| None); + winning[SlotRange::ZeroOne as u8 as usize] = Some((account_id(2), ParaId::from(2001), 900)); winning[SlotRange::ZeroThree as u8 as usize] = - Some((crowdloan_account, ParaId::from(2000), total + 900)); + Some((crowdloan_account.clone(), ParaId::from(2000), total + 900)); assert_eq!(Auctions::winning(2), Some(winning)); }) } @@ -978,7 +1164,7 @@ fn crowdloan_ending_period_bid() { #[test] fn auction_bid_requires_registered_para() { new_test_ext().execute_with(|| { - assert!(System::block_number().is_one()); // So events are emitted + assert!(System::block_number().is_one()); /* So events are emitted */ // Start a new auction in the future let duration = 99u32; @@ -986,10 +1172,10 @@ fn auction_bid_requires_registered_para() { assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start)); // Can't bid with non-registered paras - Balances::make_free_balance_be(&1, 1_000_000_000); + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); assert_noop!( Auctions::bid( - Origin::signed(1), + signed(1), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -1000,9 +1186,9 @@ fn auction_bid_requires_registered_para() { ); // Now we register the para - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), ParaId::from(2000), test_genesis_head(10), test_validation_code(10), @@ -1011,7 +1197,7 @@ fn auction_bid_requires_registered_para() { // Still can't bid until it is fully onboarded assert_noop!( Auctions::bid( - Origin::signed(1), + signed(1), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -1025,9 +1211,9 @@ fn auction_bid_requires_registered_para() { run_to_session(2); // Success - Balances::make_free_balance_be(&1, 1_000_000_000); + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); assert_ok!(Auctions::bid( - Origin::signed(1), + signed(1), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -1040,26 +1226,26 @@ fn auction_bid_requires_registered_para() { #[test] fn gap_bids_work() { new_test_ext().execute_with(|| { - assert!(System::block_number().is_one()); // So events are emitted + assert!(System::block_number().is_one()); /* So events are emitted */ // Start a new auction in the future let duration = 99u32; let lease_period_index_start = 4u32; assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start)); - Balances::make_free_balance_be(&1, 1_000_000_000); - Balances::make_free_balance_be(&2, 1_000_000_000); + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); + Balances::make_free_balance_be(&account_id(2), 1_000_000_000); // Now register 2 paras - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), ParaId::from(2000), test_genesis_head(10), test_validation_code(10), )); - assert_ok!(Registrar::reserve(Origin::signed(2))); + assert_ok!(Registrar::reserve(signed(2))); assert_ok!(Registrar::register( - Origin::signed(2), + signed(2), ParaId::from(2001), test_genesis_head(10), test_validation_code(10), @@ -1069,11 +1255,11 @@ fn gap_bids_work() { run_to_session(2); // Make bids - Balances::make_free_balance_be(&10, 1_000_000_000); - Balances::make_free_balance_be(&20, 1_000_000_000); + Balances::make_free_balance_be(&account_id(10), 1_000_000_000); + Balances::make_free_balance_be(&account_id(20), 1_000_000_000); // Slot 1 for 100 from 10 assert_ok!(Auctions::bid( - Origin::signed(10), + signed(10), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 0, // First Slot @@ -1082,7 +1268,7 @@ fn gap_bids_work() { )); // Slot 4 for 400 from 10 assert_ok!(Auctions::bid( - Origin::signed(10), + signed(10), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 3, // First Slot @@ -1092,18 +1278,18 @@ fn gap_bids_work() { // A bid for another para is counted separately. assert_ok!(Auctions::bid( - Origin::signed(10), + signed(10), ParaId::from(2001), 1, // Auction Index lease_period_index_start + 1, // First Slot lease_period_index_start + 1, // Last slot 555, // Amount )); - assert_eq!(Balances::reserved_balance(&10), 400 + 555); + assert_eq!(Balances::reserved_balance(&account_id(10)), 400 + 555); // Slot 2 for 800 from 20, overtaking 10's bid assert_ok!(Auctions::bid( - Origin::signed(20), + signed(20), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 1, // First Slot @@ -1112,7 +1298,7 @@ fn gap_bids_work() { )); // Slot 3 for 200 from 20 assert_ok!(Auctions::bid( - Origin::signed(20), + signed(20), ParaId::from(2000), 1, // Auction Index lease_period_index_start + 2, // First Slot @@ -1131,16 +1317,16 @@ fn gap_bids_work() { None, None, None, - Some((10, 100)), - Some((20, 800)), - Some((20, 200)), - Some((10, 400)) + Some((account_id(10), 100)), + Some((account_id(20), 800)), + Some((account_id(20), 200)), + Some((account_id(10), 400)) ], ); // Appropriate amount is reserved (largest of the values) - assert_eq!(Balances::reserved_balance(&10), 400); + assert_eq!(Balances::reserved_balance(&account_id(10)), 400); // Appropriate amount is reserved (largest of the values) - assert_eq!(Balances::reserved_balance(&20), 800); + assert_eq!(Balances::reserved_balance(&account_id(20)), 800); // Progress through the leases and note the correct amount of balance is reserved. @@ -1148,48 +1334,57 @@ fn gap_bids_work() { assert_eq!( slots::Leases::::get(ParaId::from(2000)), // --------- 4 -------------- 5 -------------- 6 -------------- 7 ------- - vec![Some((10, 100)), Some((20, 800)), Some((20, 200)), Some((10, 400))], + vec![ + Some((account_id(10), 100)), + Some((account_id(20), 800)), + Some((account_id(20), 200)), + Some((account_id(10), 400)) + ], ); // Nothing changed. - assert_eq!(Balances::reserved_balance(&10), 400); - assert_eq!(Balances::reserved_balance(&20), 800); + assert_eq!(Balances::reserved_balance(&account_id(10)), 400); + assert_eq!(Balances::reserved_balance(&account_id(20)), 800); // Lease period 4 is done, but nothing is unreserved since user 1 has a debt on lease 7 run_to_block(500); assert_eq!( slots::Leases::::get(ParaId::from(2000)), // --------- 5 -------------- 6 -------------- 7 ------- - vec![Some((20, 800)), Some((20, 200)), Some((10, 400))], + vec![ + Some((account_id(20), 800)), + Some((account_id(20), 200)), + Some((account_id(10), 400)) + ], ); // Nothing changed. - assert_eq!(Balances::reserved_balance(&10), 400); - assert_eq!(Balances::reserved_balance(&20), 800); + assert_eq!(Balances::reserved_balance(&account_id(10)), 400); + assert_eq!(Balances::reserved_balance(&account_id(20)), 800); // Lease period 5 is done, and 20 will unreserve down to 200. run_to_block(600); assert_eq!( slots::Leases::::get(ParaId::from(2000)), // --------- 6 -------------- 7 ------- - vec![Some((20, 200)), Some((10, 400))], + vec![Some((account_id(20), 200)), Some((account_id(10), 400))], ); - assert_eq!(Balances::reserved_balance(&10), 400); - assert_eq!(Balances::reserved_balance(&20), 200); + assert_eq!(Balances::reserved_balance(&account_id(10)), 400); + assert_eq!(Balances::reserved_balance(&account_id(20)), 200); // Lease period 6 is done, and 20 will unreserve everything. run_to_block(700); assert_eq!( slots::Leases::::get(ParaId::from(2000)), // --------- 7 ------- - vec![Some((10, 400))], + vec![Some((account_id(10), 400))], ); - assert_eq!(Balances::reserved_balance(&10), 400); - assert_eq!(Balances::reserved_balance(&20), 0); + assert_eq!(Balances::reserved_balance(&account_id(10)), 400); + assert_eq!(Balances::reserved_balance(&account_id(20)), 0); // All leases are done. Everything is unreserved. run_to_block(800); assert_eq!(slots::Leases::::get(ParaId::from(2000)), vec![]); - assert_eq!(Balances::reserved_balance(&10), 0); - assert_eq!(Balances::reserved_balance(&20), 0); + assert_eq!(Balances::reserved_balance(&account_id(10)), 0); + assert_eq!(Balances::reserved_balance(&account_id(20)), 0); }); } @@ -1198,12 +1393,12 @@ fn gap_bids_work() { #[test] fn cant_bid_on_existing_lease_periods() { new_test_ext().execute_with(|| { - assert!(System::block_number().is_one()); // So events are emitted - Balances::make_free_balance_be(&1, 1_000_000_000); + assert!(System::block_number().is_one()); /* So events are emitted */ + Balances::make_free_balance_be(&account_id(1), 1_000_000_000); // First register a parathread - assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(signed(1))); assert_ok!(Registrar::register( - Origin::signed(1), + signed(1), ParaId::from(2000), test_genesis_head(10), test_validation_code(10), @@ -1220,7 +1415,7 @@ fn cant_bid_on_existing_lease_periods() { // Open a crowdloan for Para 1 for slots 0-3 assert_ok!(Crowdloan::create( - Origin::signed(1), + signed(1), ParaId::from(2000), 1_000_000, // Cap lease_period_index_start + 0, // First Slot @@ -1228,13 +1423,14 @@ fn cant_bid_on_existing_lease_periods() { 400, // Long block end None, )); - let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000)); + let fund = Crowdloan::funds(ParaId::from(2000)).unwrap(); + let crowdloan_account = Crowdloan::fund_account_id(fund.fund_index); // Bunch of contributions let mut total = 0; for i in 10..20 { - Balances::make_free_balance_be(&i, 1_000_000_000); - assert_ok!(Crowdloan::contribute(Origin::signed(i), ParaId::from(2000), 900 - i, None)); + Balances::make_free_balance_be(&account_id(i), 1_000_000_000); + assert_ok!(Crowdloan::contribute(signed(i), ParaId::from(2000), 900 - i, None)); total += 900 - i; } assert!(total > 0); @@ -1251,8 +1447,8 @@ fn cant_bid_on_existing_lease_periods() { None, None, None, - Some((crowdloan_account, 8855)), - Some((crowdloan_account, 8855)) + Some((crowdloan_account.clone(), 8855)), + Some((crowdloan_account.clone(), 8855)) ], ); @@ -1263,7 +1459,7 @@ fn cant_bid_on_existing_lease_periods() { assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start)); // Poke the crowdloan into `NewRaise` - assert_ok!(Crowdloan::poke(Origin::signed(1), ParaId::from(2000))); + assert_ok!(Crowdloan::poke(signed(1), ParaId::from(2000))); assert_eq!(Crowdloan::new_raise(), vec![ParaId::from(2000)]); // Beginning of ending block. @@ -1272,7 +1468,7 @@ fn cant_bid_on_existing_lease_periods() { // Bids cannot be made which intersect assert_noop!( Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start + 0, @@ -1284,7 +1480,7 @@ fn cant_bid_on_existing_lease_periods() { assert_noop!( Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start + 1, @@ -1296,7 +1492,7 @@ fn cant_bid_on_existing_lease_periods() { assert_noop!( Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start - 1, @@ -1308,7 +1504,7 @@ fn cant_bid_on_existing_lease_periods() { assert_noop!( Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start + 0, @@ -1320,7 +1516,7 @@ fn cant_bid_on_existing_lease_periods() { assert_noop!( Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start + 1, @@ -1332,7 +1528,7 @@ fn cant_bid_on_existing_lease_periods() { assert_noop!( Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start - 1, @@ -1344,7 +1540,7 @@ fn cant_bid_on_existing_lease_periods() { // Will work when not overlapping assert_ok!(Auctions::bid( - Origin::signed(crowdloan_account), + Origin::signed(crowdloan_account.clone()), ParaId::from(2000), 2, lease_period_index_start + 2, diff --git a/runtime/common/src/paras_registrar.rs b/runtime/common/src/paras_registrar.rs index 3946e7d9aec5..88828283ceee 100644 --- a/runtime/common/src/paras_registrar.rs +++ b/runtime/common/src/paras_registrar.rs @@ -160,6 +160,9 @@ pub mod pallet { NotReserved, /// Registering parachain with empty code is not allowed. EmptyCode, + /// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras are + /// correct for the swap to work. + CannotSwap, } /// Pending swap operations. @@ -271,31 +274,40 @@ pub mod pallet { pub fn swap(origin: OriginFor, id: ParaId, other: ParaId) -> DispatchResult { Self::ensure_root_para_or_owner(origin, id)?; + // If `id` and `other` is the same id, we treat this as a "clear" function, and exit + // early, since swapping the same id would otherwise be a noop. + if id == other { + PendingSwap::::remove(id); + return Ok(()) + } + + // Sanity check that `id` is even a para. + let id_lifecycle = + paras::Pallet::::lifecycle(id).ok_or(Error::::NotRegistered)?; + if PendingSwap::::get(other) == Some(id) { - if let Some(other_lifecycle) = paras::Pallet::::lifecycle(other) { - if let Some(id_lifecycle) = paras::Pallet::::lifecycle(id) { - // identify which is a parachain and which is a parathread - if id_lifecycle.is_parachain() && other_lifecycle.is_parathread() { - // We check that both paras are in an appropriate lifecycle for a swap, - // so these should never fail. - let res1 = runtime_parachains::schedule_parachain_downgrade::(id); - debug_assert!(res1.is_ok()); - let res2 = runtime_parachains::schedule_parathread_upgrade::(other); - debug_assert!(res2.is_ok()); - T::OnSwap::on_swap(id, other); - } else if id_lifecycle.is_parathread() && other_lifecycle.is_parachain() { - // We check that both paras are in an appropriate lifecycle for a swap, - // so these should never fail. - let res1 = runtime_parachains::schedule_parachain_downgrade::(other); - debug_assert!(res1.is_ok()); - let res2 = runtime_parachains::schedule_parathread_upgrade::(id); - debug_assert!(res2.is_ok()); - T::OnSwap::on_swap(id, other); - } - - PendingSwap::::remove(other); - } + let other_lifecycle = + paras::Pallet::::lifecycle(other).ok_or(Error::::NotRegistered)?; + // identify which is a parachain and which is a parathread + if id_lifecycle == ParaLifecycle::Parachain && + other_lifecycle == ParaLifecycle::Parathread + { + Self::do_thread_and_chain_swap(id, other); + } else if id_lifecycle == ParaLifecycle::Parathread && + other_lifecycle == ParaLifecycle::Parachain + { + Self::do_thread_and_chain_swap(other, id); + } else if id_lifecycle == ParaLifecycle::Parachain && + other_lifecycle == ParaLifecycle::Parachain + { + // If both chains are currently parachains, there is nothing funny we + // need to do for their lifecycle management, just swap the underlying + // data. + T::OnSwap::on_swap(id, other); + } else { + return Err(Error::::CannotSwap.into()) } + PendingSwap::::remove(other); } else { PendingSwap::::insert(id, other); } @@ -564,6 +576,15 @@ impl Pallet { Ok((ParaGenesisArgs { genesis_head, validation_code, parachain }, deposit)) } + + /// Swap a parachain and parathread, which involves scheduling an appropriate lifecycle update. + fn do_thread_and_chain_swap(to_downgrade: ParaId, to_upgrade: ParaId) { + let res1 = runtime_parachains::schedule_parachain_downgrade::(to_downgrade); + debug_assert!(res1.is_ok()); + let res2 = runtime_parachains::schedule_parathread_upgrade::(to_upgrade); + debug_assert!(res2.is_ok()); + T::OnSwap::on_swap(to_upgrade, to_downgrade); + } } #[cfg(test)] @@ -587,6 +608,7 @@ mod tests { transaction_validity::TransactionPriority, Perbill, }; + use sp_std::collections::btree_map::BTreeMap; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -696,7 +718,7 @@ mod tests { type Event = Event; type Origin = Origin; type Currency = Balances; - type OnSwap = (); + type OnSwap = MockSwap; type ParaDeposit = ParaDeposit; type DataDepositPerByte = DataDepositPerByte; type WeightInfo = TestWeightInfo; @@ -724,6 +746,22 @@ mod tests { t.into() } + parameter_types! { + pub static SwapData: BTreeMap = BTreeMap::new(); + } + + pub struct MockSwap; + impl OnSwap for MockSwap { + fn on_swap(one: ParaId, other: ParaId) { + let mut swap_data = SwapData::get(); + let one_data = swap_data.remove(&one).unwrap_or_default(); + let other_data = swap_data.remove(&other).unwrap_or_default(); + swap_data.insert(one, other_data); + swap_data.insert(other, one_data); + SwapData::set(swap_data); + } + } + const BLOCKS_PER_SESSION: u32 = 3; fn run_to_block(n: BlockNumber) { @@ -997,9 +1035,15 @@ mod tests { )); run_to_session(2); - // Upgrade 1023 into a parachain + // Upgrade para 1 into a parachain assert_ok!(Registrar::make_parachain(para_1)); + // Set some mock swap data. + let mut swap_data = SwapData::get(); + swap_data.insert(para_1, 69); + swap_data.insert(para_2, 1337); + SwapData::set(swap_data); + run_to_session(4); // Roles are as we expect @@ -1014,20 +1058,15 @@ mod tests { run_to_session(6); - // Deregister a parathread that was originally a parachain - assert_eq!(Parachains::lifecycle(para_1), Some(ParaLifecycle::Parathread)); - assert_ok!(Registrar::deregister( - runtime_parachains::Origin::Parachain(para_1).into(), - para_1 - )); - - run_to_block(21); - // Roles are swapped assert!(!Parachains::is_parachain(para_1)); assert!(Parachains::is_parathread(para_1)); assert!(Parachains::is_parachain(para_2)); assert!(!Parachains::is_parathread(para_2)); + + // Data is swapped + assert_eq!(SwapData::get().get(¶_1).unwrap(), &1337); + assert_eq!(SwapData::get().get(¶_2).unwrap(), &69); }); } @@ -1059,6 +1098,121 @@ mod tests { assert_noop!(Registrar::swap(Origin::signed(1), para_id, para_id + 2), BadOrigin); }); } + + #[test] + fn swap_handles_bad_states() { + new_test_ext().execute_with(|| { + let para_1 = LOWEST_PUBLIC_ID; + let para_2 = LOWEST_PUBLIC_ID + 1; + run_to_block(1); + // paras are not yet registered + assert!(!Parachains::is_parathread(para_1)); + assert!(!Parachains::is_parathread(para_2)); + + // Cannot even start a swap + assert_noop!( + Registrar::swap(Origin::root(), para_1, para_2), + Error::::NotRegistered + ); + + // We register Paras 1 and 2 + assert_ok!(Registrar::reserve(Origin::signed(1))); + assert_ok!(Registrar::reserve(Origin::signed(2))); + assert_ok!(Registrar::register( + Origin::signed(1), + para_1, + test_genesis_head(32), + test_validation_code(32), + )); + assert_ok!(Registrar::register( + Origin::signed(2), + para_2, + test_genesis_head(32), + test_validation_code(32), + )); + + // Cannot swap + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_noop!( + Registrar::swap(Origin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(2); + + // They are now a parathread. + assert!(Parachains::is_parathread(para_1)); + assert!(Parachains::is_parathread(para_2)); + + // Cannot swap + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_noop!( + Registrar::swap(Origin::root(), para_2, para_1), + Error::::CannotSwap + ); + + // Some other external process will elevate one parathread to parachain + assert_ok!(Registrar::make_parachain(para_1)); + + // Cannot swap + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_noop!( + Registrar::swap(Origin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(3); + + // Cannot swap + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_noop!( + Registrar::swap(Origin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(4); + + // It is now a parachain. + assert!(Parachains::is_parachain(para_1)); + assert!(Parachains::is_parathread(para_2)); + + // Swap works here. + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_ok!(Registrar::swap(Origin::root(), para_2, para_1)); + + run_to_session(5); + + // Cannot swap + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_noop!( + Registrar::swap(Origin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(6); + + // Swap worked! + assert!(Parachains::is_parachain(para_2)); + assert!(Parachains::is_parathread(para_1)); + + // Something starts to downgrade a para + assert_ok!(Registrar::make_parathread(para_2)); + + run_to_session(7); + + // Cannot swap + assert_ok!(Registrar::swap(Origin::root(), para_1, para_2)); + assert_noop!( + Registrar::swap(Origin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(8); + + assert!(Parachains::is_parathread(para_1)); + assert!(Parachains::is_parathread(para_2)); + }); + } } #[cfg(feature = "runtime-benchmarks")] diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 249b43f778fb..42c8d5137585 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -138,11 +138,11 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -/// Don't allow swaps until parathread story is more mature. +/// We currently allow all calls. pub struct BaseFilter; impl Contains for BaseFilter { - fn contains(c: &Call) -> bool { - !matches!(c, Call::Registrar(paras_registrar::Call::swap { .. })) + fn contains(_c: &Call) -> bool { + true } } @@ -1497,7 +1497,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (SchedulerMigrationV3, RefundNickPalletDeposit), + (SchedulerMigrationV3, RefundNickPalletDeposit, CrowdloanIndexMigration), >; /// The payload being signed in the transactions. pub type SignedPayload = generic::SignedPayload; @@ -2929,6 +2929,24 @@ impl OnRuntimeUpgrade for SchedulerMigrationV3 { } } +// Migration for crowdloan pallet to use fund index for account generation. +pub struct CrowdloanIndexMigration; +impl OnRuntimeUpgrade for CrowdloanIndexMigration { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + crowdloan::migration::crowdloan_index_migration::migrate::() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::pre_migrate::() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::post_migrate::() + } +} + /// Migrate session-historical from `Session` to the new pallet prefix `Historical` pub struct SessionHistoricalPalletPrefixMigration; diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index 09d74520ed28..a1c5175bf300 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -1446,11 +1446,29 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (SchedulerMigrationV3, FixCouncilDepositMigration), + (SchedulerMigrationV3, FixCouncilDepositMigration, CrowdloanIndexMigration), >; /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; +// Migration for crowdloan pallet to use fund index for account generation. +pub struct CrowdloanIndexMigration; +impl OnRuntimeUpgrade for CrowdloanIndexMigration { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + crowdloan::migration::crowdloan_index_migration::migrate::() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::pre_migrate::() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::post_migrate::() + } +} + /// A migration struct to fix some deposits in the council election pallet. /// /// See more details here: https://github.com/paritytech/polkadot/issues/4160 diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index fa65abcc23ce..021d66c37418 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -154,11 +154,29 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (SessionHistoricalModulePrefixMigration,), + (SessionHistoricalModulePrefixMigration, CrowdloanIndexMigration), >; /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; +// Migration for crowdloan pallet to use fund index for account generation. +pub struct CrowdloanIndexMigration; +impl OnRuntimeUpgrade for CrowdloanIndexMigration { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + crowdloan::migration::crowdloan_index_migration::migrate::() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::pre_migrate::() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::post_migrate::() + } +} + /// Migrate session-historical from `Session` to the new pallet prefix `Historical` pub struct SessionHistoricalModulePrefixMigration; diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index eb5af15c4af5..dc19bdd05bc8 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -1084,11 +1084,29 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - (SessionHistoricalPalletPrefixMigration, SchedulerMigrationV3), + (SessionHistoricalPalletPrefixMigration, SchedulerMigrationV3, CrowdloanIndexMigration), >; /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; +// Migration for crowdloan pallet to use fund index for account generation. +pub struct CrowdloanIndexMigration; +impl OnRuntimeUpgrade for CrowdloanIndexMigration { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + crowdloan::migration::crowdloan_index_migration::migrate::() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::pre_migrate::() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + crowdloan::migration::crowdloan_index_migration::post_migrate::() + } +} + // Migration for scheduler pallet to move from a plain Call to a CallOrHash. pub struct SchedulerMigrationV3;