Newer
Older
// Copyright 2019-2021 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.
use crate::{
auctions, crowdloan, paras_registrar,
slot_range::SlotRange,
slots,
traits::{AuctionStatus, Auctioneer, Registrar as RegistrarT},
assert_noop, assert_ok, parameter_types,
traits::{Currency, GenesisBuild, KeyOwnerProofSystem, OnFinalize, OnInitialize},
PalletId,
};
use frame_support_test::TestRandomness;
use frame_system::EnsureRoot;
use primitives::v1::{
BlockNumber, HeadData, Header, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID,
use runtime_parachains::{
configuration, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle,
};
use sp_core::{crypto::KeyTypeId, H256};
use sp_io::TestExternalities;
use sp_keystore::{testing::KeyStore, KeystoreExt};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup, One},
transaction_validity::TransactionPriority,
};
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
type AccountId = u32;
type Balance = u32;
type Moment = u32;
frame_support::construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
// System Stuff
Shaun Wang
committed
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned},
Shaun Wang
committed
Configuration: configuration::{Pallet, Call, Storage, Config<T>},
Paras: paras::{Pallet, Call, Storage, Event, Config},
ParasShared: shared::{Pallet, Call, Storage},
ParachainsOrigin: origin::{Pallet, Origin},
Shaun Wang
committed
Registrar: paras_registrar::{Pallet, Call, Storage, Event<T>},
Auctions: auctions::{Pallet, Call, Storage, Event<T>},
Crowdloan: crowdloan::{Pallet, Call, Storage, Event<T>},
Slots: slots::{Pallet, Call, Storage, Event<T>},
impl<C> frame_system::offchain::SendTransactionTypes<C> for Test
where
Call: From<C>,
{
type Extrinsic = UncheckedExtrinsic;
type OverarchingCall = Call;
}
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(4 * 1024 * 1024);
}
impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = BlockWeights;
type BlockLength = ();
type DbWeight = ();
type Origin = Origin;
type Call = Call;
type Index = u64;
type BlockNumber = BlockNumber;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<AccountId>;
type Header = Header;
type Event = Event;
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 KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
pallet_babe::AuthorityId,
)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
pallet_babe::AuthorityId,
)>>::IdentificationTuple;
type HandleEquivocation = ();
type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;
}
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 Event = Event;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
impl configuration::Config for Test {
type WeightInfo = configuration::TestWeightInfo;
impl origin::Config for Test {}
parameter_types! {
pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
}
type WeightInfo = paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority;
type NextSessionRotation = crate::mock::TestNextSessionRotation;
}
parameter_types! {
pub const ParaDeposit: Balance = 500;
pub const DataDepositPerByte: Balance = 1;
}
impl paras_registrar::Config for Test {
type Event = Event;
type OnSwap = (Crowdloan, Slots);
type ParaDeposit = ParaDeposit;
type DataDepositPerByte = DataDepositPerByte;
type Currency = Balances;
type Origin = Origin;
type WeightInfo = crate::paras_registrar::TestWeightInfo;
}
parameter_types! {
pub const EndingPeriod: BlockNumber = 10;
pub const SampleLength: BlockNumber = 1;
}
impl auctions::Config for Test {
type Event = Event;
type Leaser = Slots;
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 = 0;
}
impl slots::Config for Test {
type Event = Event;
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 Event = Event;
type SubmissionDeposit = SubmissionDeposit;
type MinContribution = MinContribution;
type RemoveKeysLimit = RemoveKeysLimit;
type Registrar = Registrar;
type Auctioneer = Auctions;
type MaxMemoLength = MaxMemoLength;
type WeightInfo = crate::crowdloan::TestWeightInfo;
}
/// Create a new set of test externalities.
pub fn new_test_ext() -> TestExternalities {
Shawn Tabrizi
committed
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
GenesisBuild::<Test>::assimilate_storage(
&configuration::GenesisConfig {
config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB
max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default()
let keystore = KeyStore::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;
fn maybe_new_session(n: u32) {
if n % BLOCKS_PER_SESSION == 0 {
shared::Pallet::<Test>::set_session_index(shared::Pallet::<Test>::session_index() + 1);
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 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() -> Event {
System::events().pop().expect("Event expected").event
}
fn contains_event(event: Event) -> 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() {
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
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());
// 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);
// 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::register(
Origin::signed(1),
ParaId::from(para_1),
genesis_head.clone(),
validation_code.clone(),
));
assert_ok!(Registrar::reserve(Origin::signed(2)));
assert_ok!(Registrar::register(
Origin::signed(2),
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(Origin::root(), duration, lease_period_index_start));
// 2 sessions later they are parathreads
run_to_session(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(
Origin::signed(2),
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 crowdloan_account = Crowdloan::fund_account_id(ParaId::from(para_2));
// 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);
// User 10 will bid directly for parachain 1
assert_ok!(Auctions::bid(
Origin::signed(10),
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(&2, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::signed(2), ParaId::from(para_2), 920, None));
// Auction ends at block 110 + offset
run_to_block(109 + offset);
assert!(contains_event(
crowdloan::Event::<Test>::HandleBidResult(ParaId::from(para_2), Ok(())).into()
));
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
run_to_block(110 + offset);
assert_eq!(last_event(), auctions::Event::<Test>::AuctionClosed(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((10, 910)), Some((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, 920)),
Some((crowdloan_account, 920))
],
);
// Should not be able to contribute to a winning crowdloan
Balances::make_free_balance_be(&3, 1_000_000_000);
assert_noop!(
Crowdloan::contribute(Origin::signed(3), ParaId::from(2001), 10, None),
CrowdloanError::<Test>::BidOrLeaseActive
);
// New leases will start on block 400
let lease_start_block = 400 + offset;
run_to_block(lease_start_block);
// First slot, Para 1 should be transitioning to Parachain
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;
Shawn Tabrizi
committed
Balances::make_free_balance_be(&1, 1_000_000_000);
Balances::make_free_balance_be(&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::register(
Origin::signed(1),
genesis_head.clone(),
validation_code.clone(),
));
assert_ok!(Registrar::reserve(Origin::signed(2)));
assert_noop!(
Registrar::register(Origin::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(Origin::root(), duration, lease_period_index_start));
// Cannot create a crowdloan if you do not own the para
assert_noop!(
Crowdloan::create(
Origin::signed(2),
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;
Shawn Tabrizi
committed
Balances::make_free_balance_be(&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::register(
Origin::signed(n),
para_id + n - 1,
genesis_head,
validation_code,
));
}
// Start a new auction in the future
let duration = 149u32;
let lease_period_index_start = 4u32;
assert_ok!(Auctions::new_auction(Origin::root(), duration, lease_period_index_start));
// Paras should be onboarded
run_to_block(20); // session 2
run_to_block(System::block_number() + 10);
Balances::make_free_balance_be(&(n * 10), n * 1_000);
let (start, end) = match n {
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
assert_ok!(Auctions::bid(
Origin::signed(n * 10),
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(160);
// 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((10, 900))],
);
assert_eq!(
slots::Leases::<Test>::get(para_id + 4),
// -- 1 --- 2 --- 3 --- 4 ---------- 5 -------
vec![None, None, None, None, Some((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((90, 8100)), Some((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());
let start_para = LOWEST_PUBLIC_ID - 1;
Shawn Tabrizi
committed
Balances::make_free_balance_be(&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::register(
Origin::signed(n),
ParaId::from(start_para + n),
genesis_head,
validation_code,
));
}
// Finish registration of paras.
run_to_session(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(Origin::root(), duration, lease_period_index_start));
// Create a crowdloan for each para
assert_ok!(Crowdloan::create(
Origin::signed(n),
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(&(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),
ParaId::from(para),
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
assert_ok!(Crowdloan::contribute(
Origin::signed(n * 10),
ParaId::from(para),
n + 900,
None,
));
}
}
// Auction should be done
run_to_block(starting_block + 110);
// Appropriate Paras should have won slots
let crowdloan_2 = Crowdloan::fund_account_id(ParaId::from(2001));
slots::Leases::<Test>::get(ParaId::from(2000)),
// -- 1 --- 2 --- 3 --- 4 --- 5 ------------- 6 ------------------------ 7 -------------
vec![
None,
None,
None,
None,
None,
Some((crowdloan_2, 1812)),
Some((crowdloan_2, 1812))
],
slots::Leases::<Test>::get(ParaId::from(2002)),
// -- 1 --- 2 --- 3 ---------- 4 --------------- 5 -------
vec![None, None, None, Some((80, 7200)), Some((80, 7200))],
);
});
}
#[test]
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
Shawn Tabrizi
committed
Balances::make_free_balance_be(&1, 1_000_000_000);
Balances::make_free_balance_be(&2, 1_000_000_000);
// First register 2 parathreads with different data
assert_ok!(Registrar::reserve(Origin::signed(1)));
assert_ok!(Registrar::register(
Origin::signed(1),
ParaId::from(2000),
test_genesis_head(10),
test_validation_code(10),
));
assert_ok!(Registrar::reserve(Origin::signed(2)));
assert_ok!(Registrar::register(
Origin::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));
// 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));
// 2 sessions later they are parathreads
run_to_session(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(
Origin::signed(1),
ParaId::from(2000),
lease_period_index_start + 0, // First Slot
lease_period_index_start + 3, // Last Slot
let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000));
// Bunch of contributions
let mut total = 0;
Shawn Tabrizi
committed
Balances::make_free_balance_be(&i, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::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
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(&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));
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);
// Crowdloan ownership is swapped
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());
assert_noop!(
Crowdloan::dissolve(Origin::signed(1), ParaId::from(2000)),
CrowdloanError::<Test>::InvalidParaId
);
assert_noop!(
Crowdloan::dissolve(Origin::signed(2), ParaId::from(2001)),
CrowdloanError::<Test>::NotReadyToDissolve
);
// Go way in the future when the para is offboarded
run_to_block(lease_start_block + 1000);
// Withdraw of contributions works
assert_eq!(Balances::free_balance(&crowdloan_account), total);
assert_ok!(Crowdloan::withdraw(Origin::signed(i), 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);
// 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);
})
}
#[test]
fn crowdloan_ending_period_bid() {
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one()); // So events are emitted
Shawn Tabrizi
committed
Balances::make_free_balance_be(&1, 1_000_000_000);
Balances::make_free_balance_be(&2, 1_000_000_000);
assert_ok!(Registrar::reserve(Origin::signed(1)));
assert_ok!(Registrar::register(
Origin::signed(1),
ParaId::from(2000),
test_genesis_head(10),
test_validation_code(10),
));
assert_ok!(Registrar::reserve(Origin::signed(2)));
assert_ok!(Registrar::register(
Origin::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));
// 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));
// 2 sessions later they are parathreads
run_to_session(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(
Origin::signed(1),
ParaId::from(2000),
lease_period_index_start + 0, // First Slot
lease_period_index_start + 3, // Last Slot
let crowdloan_account = Crowdloan::fund_account_id(ParaId::from(2000));
// Bunch of contributions
let mut total = 0;
Shawn Tabrizi
committed
Balances::make_free_balance_be(&i, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::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
Shawn Tabrizi
committed
Balances::make_free_balance_be(&2, 1_000_000_000);
assert_ok!(Auctions::bid(
Origin::signed(2),
ParaId::from(2001),
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
));
// Go to beginning of ending period
run_to_block(100);
assert_eq!(Auctions::auction_status(100), AuctionStatus::<u32>::EndingPeriod(0, 0));
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(2001), 900));
winning[SlotRange::ZeroThree as u8 as usize] =
Some((crowdloan_account, ParaId::from(2000), total));
assert_eq!(Auctions::winning(0), Some(winning));
Shawn Tabrizi
committed
Balances::make_free_balance_be(&1234, 1_000_000_000);
assert_ok!(Crowdloan::contribute(Origin::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));
winning[SlotRange::ZeroThree as u8 as usize] =
Some((crowdloan_account, ParaId::from(2000), total + 900));
assert_eq!(Auctions::winning(2), Some(winning));
#[test]
fn auction_bid_requires_registered_para() {
new_test_ext().execute_with(|| {
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));
// Can't bid with non-registered paras
Shawn Tabrizi
committed
Balances::make_free_balance_be(&1, 1_000_000_000);
assert_noop!(
Auctions::bid(
Origin::signed(1),
ParaId::from(2000),
1, // Auction Index
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
900, // Amount
),
AuctionsError::<Test>::ParaNotRegistered
);