Newer
Older
// Copyright (C) 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 <http://www.gnu.org/licenses/>.
//! Mocking utilities for testing with real pallets.
auctions, crowdloan, identity_migrator,
mock::{conclude_pvf_checking, validators_public_keys},
paras_registrar,
traits::{AuctionStatus, Auctioneer, Leaser, Registrar as RegistrarT},
assert_noop, assert_ok, derive_impl, parameter_types,
traits::{ConstU32, Currency, OnFinalize, OnInitialize},
};
use frame_support_test::TestRandomness;
use pallet_identity::{self, legacy::IdentityInfo};
use primitives::{
BlockNumber, HeadData, Id as ParaId, SessionIndex, ValidationCode, LOWEST_PUBLIC_ID,
use runtime_parachains::{
configuration, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle,
};
use sp_keyring::Sr25519Keyring;
use sp_keystore::{testing::MemoryKeystore, KeystoreExt};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup, One, Verify},
transaction_validity::TransactionPriority,
AccountId32, BuildStorage, MultiSignature,
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlockU32<Test>;
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()
}
pub enum Test
System: frame_system,
Balances: pallet_balances,
Babe: pallet_babe,
Configuration: configuration,
Paras: paras,
ParasShared: shared,
ParachainsOrigin: origin,
Registrar: paras_registrar,
Auctions: auctions,
Crowdloan: crowdloan,
Slots: slots,
Identity: pallet_identity,
IdentityMigrator: identity_migrator,
impl<C> frame_system::offchain::SendTransactionTypes<C> for Test
where
{
type Extrinsic = UncheckedExtrinsic;
}
use crate::{auctions::Error as AuctionsError, crowdloan::Error as CrowdloanError};
parameter_types! {
pub const BlockHashCount: u32 = 250;
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = BlockWeights;
type BlockLength = ();
type DbWeight = ();
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<AccountId>;
type Block = Block;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
parameter_types! {
pub const EpochDuration: u64 = 10;
pub const ExpectedBlockTime: Moment = 6_000;
pub const ReportLongevity: u64 = 10;
pub const MaxAuthorities: u32 = 100_000;
}
impl pallet_babe::Config for Test {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
type MaxAuthorities = MaxAuthorities;
type KeyOwnerProof = sp_core::Void;
type EquivocationReportSystem = ();
}
parameter_types! {
pub const MinimumPeriod: Moment = 6_000 / 2;
}
impl pallet_timestamp::Config for Test {
type Moment = Moment;
type OnTimestampSet = ();
type MinimumPeriod = MinimumPeriod;
type WeightInfo = ();
}
parameter_types! {
pub static ExistentialDeposit: Balance = 1;
}
impl pallet_balances::Config for Test {
type MaxLocks = ();
type Balance = Balance;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
type RuntimeHoldReason = RuntimeHoldReason;
type RuntimeFreezeReason = RuntimeFreezeReason;
type FreezeIdentifier = ();
type MaxHolds = ConstU32<0>;
type MaxFreezes = ConstU32<0>;
impl configuration::Config for Test {
type WeightInfo = configuration::TestWeightInfo;
Tsvetomir Dimitrov
committed
impl shared::Config for Test {
type DisabledValidators = ();
}
impl origin::Config for Test {}
parameter_types! {
pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
}
type WeightInfo = paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ();
type NextSessionRotation = crate::mock::TestNextSessionRotation;
type OnNewHead = ();
}
parameter_types! {
pub const ParaDeposit: Balance = 500;
pub const DataDepositPerByte: Balance = 1;
}
impl paras_registrar::Config for Test {
type OnSwap = (Crowdloan, Slots);
type ParaDeposit = ParaDeposit;
type DataDepositPerByte = DataDepositPerByte;
type Currency = Balances;
type WeightInfo = crate::paras_registrar::TestWeightInfo;
}
parameter_types! {
pub const EndingPeriod: BlockNumber = 10;
pub const SampleLength: BlockNumber = 1;
}
impl auctions::Config for Test {
type Registrar = Registrar;
type SampleLength = SampleLength;
type Randomness = TestRandomness<Self>;
type InitiateOrigin = EnsureRoot<AccountId>;
type WeightInfo = crate::auctions::TestWeightInfo;
}
parameter_types! {
pub const LeasePeriod: BlockNumber = 100;
pub static LeaseOffset: BlockNumber = 5;
}
impl slots::Config for Test {
type Currency = Balances;
type Registrar = Registrar;
type LeasePeriod = LeasePeriod;
type LeaseOffset = LeaseOffset;
type ForceOrigin = EnsureRoot<AccountId>;
type WeightInfo = crate::slots::TestWeightInfo;
}
parameter_types! {
pub const CrowdloanId: PalletId = PalletId(*b"py/cfund");
pub const SubmissionDeposit: Balance = 100;
pub const MinContribution: Balance = 1;
pub const RemoveKeysLimit: u32 = 100;
pub const MaxMemoLength: u8 = 32;
}
impl crowdloan::Config for Test {
type SubmissionDeposit = SubmissionDeposit;
type MinContribution = MinContribution;
type RemoveKeysLimit = RemoveKeysLimit;
type Registrar = Registrar;
type Auctioneer = Auctions;
type MaxMemoLength = MaxMemoLength;
type WeightInfo = crate::crowdloan::TestWeightInfo;
}
impl pallet_identity::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type Slashed = ();
type BasicDeposit = ConstU32<100>;
type ByteDeposit = ConstU32<10>;
type SubAccountDeposit = ConstU32<100>;
type MaxSubAccounts = ConstU32<2>;
type IdentityInformation = IdentityInfo<ConstU32<2>>;
type MaxRegistrars = ConstU32<20>;
type RegistrarOrigin = EnsureRoot<AccountId>;
type ForceOrigin = EnsureRoot<AccountId>;
type OffchainSignature = MultiSignature;
type SigningPublicKey = <MultiSignature as Verify>::Signer;
type UsernameAuthorityOrigin = EnsureRoot<AccountId>;
type PendingUsernameExpiration = ConstU32<100>;
type MaxSuffixLength = ConstU32<7>;
type MaxUsernameLength = ConstU32<32>;
type WeightInfo = ();
}
impl identity_migrator::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Reaper = EnsureRoot<AccountId>;
type ReapIdentityHandler = ();
type WeightInfo = crate::identity_migrator::TestWeightInfo;
}
/// Create a new set of test externalities.
pub fn new_test_ext() -> TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
configuration::GenesisConfig::<Test> {
config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB
max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default()
}
.assimilate_storage(&mut t)
let keystore = MemoryKeystore::new();
let mut ext: sp_io::TestExternalities = t.into();
ext.register_extension(KeystoreExt(Arc::new(keystore)));
ext.execute_with(|| System::set_block_number(1));
ext
}
#[cfg(feature = "runtime-benchmarks")]
pub fn new_test_ext_with_offset(n: BlockNumber) -> TestExternalities {
LeaseOffset::set(n);
new_test_ext()
}
const BLOCKS_PER_SESSION: u32 = 10;
const VALIDATORS: &[Sr25519Keyring] = &[
Sr25519Keyring::Alice,
Sr25519Keyring::Bob,
Sr25519Keyring::Charlie,
Sr25519Keyring::Dave,
Sr25519Keyring::Ferdie,
];
fn maybe_new_session(n: u32) {
if n % BLOCKS_PER_SESSION == 0 {
let session_index = shared::Pallet::<Test>::session_index() + 1;
let validators_pub_keys = validators_public_keys(VALIDATORS);
shared::Pallet::<Test>::set_session_index(session_index);
shared::Pallet::<Test>::set_active_validators_ascending(validators_pub_keys);
Paras::test_on_new_session();
}
}
fn test_genesis_head(size: usize) -> HeadData {
HeadData(vec![0u8; size])
}
fn test_validation_code(size: usize) -> ValidationCode {
let validation_code = vec![0u8; size as usize];
ValidationCode(validation_code)
}
fn para_origin(id: u32) -> ParaOrigin {
ParaOrigin::Parachain(id.into())
}
fn add_blocks(n: u32) {
let block_number = System::block_number();
run_to_block(block_number + n);
}
fn run_to_block(n: u32) {
assert!(System::block_number() < n);
while System::block_number() < n {
let block_number = System::block_number();
AllPalletsWithSystem::on_finalize(block_number);
System::set_block_number(block_number + 1);
maybe_new_session(block_number + 1);
AllPalletsWithSystem::on_initialize(block_number + 1);
}
}
fn run_to_session(n: u32) {
let block_number = BLOCKS_PER_SESSION * n;
run_to_block(block_number);
}
fn last_event() -> RuntimeEvent {
System::events().pop().expect("RuntimeEvent expected").event
fn contains_event(event: RuntimeEvent) -> bool {
System::events().iter().any(|x| x.event == event)
}
// Runs an end to end test of the auction, crowdloan, slots, and onboarding process over varying
// lease period offsets.
#[test]
fn basic_end_to_end_works() {
for offset in [0u32, 50, 100, 200].iter() {
LeaseOffset::set(*offset);
new_test_ext().execute_with(|| {
let para_1 = LOWEST_PUBLIC_ID;
let para_2 = LOWEST_PUBLIC_ID + 1;
assert!(System::block_number().is_one());
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
let start_block = System::block_number();
// User 1 and 2 will own parachains
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 on-demand parachains
let genesis_head = Registrar::worst_head_data();
let validation_code = Registrar::worst_validation_code();
assert_ok!(Registrar::reserve(signed(1)));
assert_ok!(Registrar::register(
ParaId::from(para_1),
genesis_head.clone(),
validation_code.clone(),
));
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
assert_ok!(Registrar::reserve(signed(2)));
assert_ok!(Registrar::register(
ParaId::from(2001),
genesis_head,
validation_code,
));
// Paras should be onboarding
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Onboarding));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Onboarding));
// Start a new auction in the future
let duration = 99u32 + offset;
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(
RuntimeOrigin::root(),
duration,
lease_period_index_start
));
// 2 sessions later they are parathreads (on-demand parachains)
run_to_session(START_SESSION_INDEX + 2);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread));
// Para 1 will bid directly for slot 1, 2
// Open a crowdloan for Para 2 for slot 3, 4
assert_ok!(Crowdloan::create(
ParaId::from(para_2),
1_000, // Cap
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
200 + offset, // Block End
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(start_block + 90 + offset);
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(
ParaId::from(para_1),
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
910, // Amount
));
// User 2 will be a contribute to crowdloan for parachain 2
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(start_block + 109 + offset);
crowdloan::Event::<Test>::HandleBidResult {
para_id: ParaId::from(para_2),
result: Ok(())
}
.into()
run_to_block(start_block + 110 + offset);
assert_eq!(
last_event(),
auctions::Event::<Test>::AuctionClosed { auction_index: 1 }.into()
);
// Paras should have won slots
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(para_1)),
// -- 1 --- 2 --- 3 --------- 4 ------------ 5 --------
vec![None, None, None, Some((account_id(10), 910)), Some((account_id(10), 910))],
);
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(para_2)),
// -- 1 --- 2 --- 3 --- 4 --- 5 ---------------- 6 --------------------------- 7
// ----------------
vec![
None,
None,
None,
None,
None,
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(&account_id(3), 1_000_000_000);
Crowdloan::contribute(signed(3), ParaId::from(2001), 10, None),
CrowdloanError::<Test>::BidOrLeaseActive
);
// New leases will start on block 400
let lease_start_block = start_block + 400 + offset;
run_to_block(lease_start_block);
// First slot, Para 1 should be transitioning to lease holding Parachain
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
assert_eq!(
Paras::lifecycle(ParaId::from(para_1)),
Some(ParaLifecycle::UpgradingParathread)
);
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread));
// Two sessions later, it has upgraded
run_to_block(lease_start_block + 20);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parachain));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread));
// Second slot nothing happens :)
run_to_block(lease_start_block + 100);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parachain));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread));
// Third slot, Para 2 should be upgrading, and Para 1 is downgrading
run_to_block(lease_start_block + 200);
assert_eq!(
Paras::lifecycle(ParaId::from(para_1)),
Some(ParaLifecycle::DowngradingParachain)
);
assert_eq!(
Paras::lifecycle(ParaId::from(para_2)),
Some(ParaLifecycle::UpgradingParathread)
);
// Two sessions later, they have transitioned
run_to_block(lease_start_block + 220);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parachain));
// Fourth slot nothing happens :)
run_to_block(lease_start_block + 300);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parachain));
// Fifth slot, Para 2 is downgrading
run_to_block(lease_start_block + 400);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread));
assert_eq!(
Paras::lifecycle(ParaId::from(para_2)),
Some(ParaLifecycle::DowngradingParachain)
);
// Two sessions later, Para 2 is downgraded
run_to_block(lease_start_block + 420);
assert_eq!(Paras::lifecycle(ParaId::from(para_1)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(para_2)), Some(ParaLifecycle::Parathread));
});
}
}
#[test]
fn basic_errors_fail() {
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one());
let para_id = LOWEST_PUBLIC_ID;
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(signed(1)));
genesis_head.clone(),
validation_code.clone(),
));
assert_ok!(Registrar::reserve(signed(2)));
Registrar::register(signed(2), para_id, genesis_head, validation_code,),
paras_registrar::Error::<Test>::NotOwner
);
// Start an auction
let duration = 99u32;
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(
RuntimeOrigin::root(),
duration,
lease_period_index_start
));
// Cannot create a crowdloan if you do not own the para
para_id,
1_000, // Cap
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
None,
),
crowdloan::Error::<Test>::InvalidOrigin
);
});
}
#[test]
fn competing_slots() {
// This test will verify that competing slots, from different sources will resolve
// appropriately.
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one());
let max_bids = 10u32;
let para_id = LOWEST_PUBLIC_ID;
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
let validation_code = Registrar::worst_validation_code();
Balances::make_free_balance_be(&account_id(n), 1_000_000_000);
let genesis_head = Registrar::worst_head_data();
assert_ok!(Registrar::reserve(signed(n)));
para_id + n - 1,
validation_code.clone(),
// The code undergoing the prechecking is the same for all paras.
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
// Start a new auction in the future
let duration = 149u32;
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(
RuntimeOrigin::root(),
duration,
lease_period_index_start
));
// Paras should be onboarded
run_to_session(START_SESSION_INDEX + 2);
run_to_block(System::block_number() + 10);
Balances::make_free_balance_be(&account_id(n * 10), n * 1_000);
1 => (0, 0),
2 => (0, 1),
3 => (0, 2),
4 => (0, 3),
5 => (1, 1),
6 => (1, 2),
7 => (1, 3),
8 => (2, 2),
9 => (2, 3),
10 => (3, 3),
_ => panic!("test not meant for this"),
};
// Users will bid directly for parachain
para_id + n - 1,
lease_period_index_start + start, // First Slot
lease_period_index_start + end, // Last slot
n * 900, // Amount
// Auction should be done after ending period
run_to_block(180);
// Appropriate Paras should have won slots
// 900 + 4500 + 2x 8100 = 21,600
// 900 + 4500 + 7200 + 9000 = 21,600
assert_eq!(
slots::Leases::<Test>::get(para_id),
// -- 1 --- 2 --- 3 ---------- 4 ------
vec![None, None, None, Some((account_id(10), 900))],
slots::Leases::<Test>::get(para_id + 4),
// -- 1 --- 2 --- 3 --- 4 ---------- 5 -------
vec![None, None, None, None, Some((account_id(50), 4500))],
);
// TODO: Is this right?
assert_eq!(
slots::Leases::<Test>::get(para_id + 8),
// -- 1 --- 2 --- 3 --- 4 --- 5 ---------- 6 --------------- 7 -------
vec![
None,
None,
None,
None,
None,
Some((account_id(90), 8100)),
Some((account_id(90), 8100))
],
);
});
}
#[test]
fn competing_bids() {
// This test will verify that competing bids, from different sources will resolve appropriately.
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one());
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
let start_para = LOWEST_PUBLIC_ID - 1;
let validation_code = Registrar::worst_validation_code();
Balances::make_free_balance_be(&account_id(n), 1_000_000_000);
let genesis_head = Registrar::worst_head_data();
assert_ok!(Registrar::reserve(signed(n)));
ParaId::from(start_para + n),
validation_code.clone(),
}
// The code undergoing the prechecking is the same for all paras.
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
// Finish registration of paras.
run_to_session(START_SESSION_INDEX + 2);
// Start a new auction in the future
let starting_block = System::block_number();
let duration = 99u32;
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(
RuntimeOrigin::root(),
duration,
lease_period_index_start
));
// Create a crowdloan for each para
assert_ok!(Crowdloan::create(
ParaId::from(start_para + n),
lease_period_index_start + 2, // First Slot
lease_period_index_start + 3, // Last Slot
run_to_block(starting_block + n * 10);
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(
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
// User 20 will be a contribute to crowdloan for parachain 2
ParaId::from(para),
n + 900,
None,
));
}
}
// Auction should be done
run_to_block(starting_block + 110);
// Appropriate Paras should have won slots
let fund_1 = Crowdloan::funds(ParaId::from(2000)).unwrap();
let crowdloan_1 = Crowdloan::fund_account_id(fund_1.fund_index);
slots::Leases::<Test>::get(ParaId::from(2000)),
// -- 1 --- 2 --- 3 --- 4 --- 5 ------------- 6 ------------------------ 7
// -------------
vec![
None,
None,
None,
None,
None,
Some((crowdloan_1.clone(), 1812)),
Some((crowdloan_1.clone(), 1812))
slots::Leases::<Test>::get(ParaId::from(2002)),
// -- 1 --- 2 --- 3 ---------- 4 --------------- 5 -------
vec![None, None, None, Some((account_id(80), 7200)), Some((account_id(80), 7200))],
);
});
}
#[test]
fn basic_swap_works() {
// This test will test a swap between a lease holding parachain and on-demand parachain works
// successfully.
assert!(System::block_number().is_one()); /* So events are emitted */
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
// 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 on-demand parachains with different data
let validation_code = test_validation_code(10);
assert_ok!(Registrar::reserve(signed(1)));
ParaId::from(2000),
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
let validation_code = test_validation_code(20);
assert_ok!(Registrar::reserve(signed(2)));
ParaId::from(2001),
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Onboarding));
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Onboarding));
// Start a new auction in the future
let duration = 99u32;
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(
RuntimeOrigin::root(),
duration,
lease_period_index_start
));
// 2 sessions later they are on-demand parachains
run_to_session(START_SESSION_INDEX + 2);
assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parathread));
// Open a crowdloan for Para 1 for slots 0-3
assert_ok!(Crowdloan::create(
ParaId::from(2000),
lease_period_index_start + 0, // First Slot
lease_period_index_start + 3, // Last Slot
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;
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);
// Go to end of auction where everyone won their slots
run_to_block(200);
// Deposit is appropriately taken
// ----------------------------------------- para deposit --- crowdloan
let crowdloan_deposit = 100;
let para_id_deposit = <Test as paras_registrar::Config>::ParaDeposit::get();
let code_deposit = configuration::Pallet::<Test>::config().max_code_size *
<Test as paras_registrar::Config>::DataDepositPerByte::get();
// Para 2000 has a genesis head size of 10.
assert_eq!(
Balances::reserved_balance(&account_id(1)),
crowdloan_deposit + para_id_deposit + code_deposit + 10
);
// Para 2001 has a genesis head size of 20.
assert_eq!(Balances::reserved_balance(&account_id(2)), para_id_deposit + code_deposit + 20);
assert_eq!(Balances::reserved_balance(&crowdloan_account), total);
// Crowdloan is appropriately set
assert!(Crowdloan::funds(ParaId::from(2000)).is_some());
assert!(Crowdloan::funds(ParaId::from(2001)).is_none());
// New leases will start on block 400
let lease_start_block = 400;
run_to_block(lease_start_block);
// 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(lease_start_block + 20);
assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parachain));
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parathread));
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)
));
assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::DowngradingParachain));
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::UpgradingParathread));
// 2 session later they have swapped
run_to_block(lease_start_block + 40);
assert_eq!(Paras::lifecycle(ParaId::from(2000)), Some(ParaLifecycle::Parathread));
assert_eq!(Paras::lifecycle(ParaId::from(2001)), Some(ParaLifecycle::Parachain));
// Deregister on-demand parachain
assert_ok!(Registrar::deregister(para_origin(2000).into(), ParaId::from(2000)));
assert_eq!(Balances::reserved_balance(&account_id(1)), crowdloan_deposit);
assert_eq!(Balances::reserved_balance(&account_id(2)), para_id_deposit + code_deposit + 20);
assert!(Crowdloan::funds(ParaId::from(2000)).is_none());
assert!(Crowdloan::funds(ParaId::from(2001)).is_some());
assert!(Slots::lease(ParaId::from(2000)).is_empty());
assert!(!Slots::lease(ParaId::from(2001)).is_empty());
Crowdloan::dissolve(signed(1), ParaId::from(2000)),
CrowdloanError::<Test>::InvalidParaId
);
assert_noop!(