Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
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!(
<Slots as Leaser<_>>::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::<Test>::get(ParaId::from(2000)).len(), 6);
assert_eq!(slots::Leases::<Test>::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(&account_id(1), 1_000_000_000);
Balances::make_free_balance_be(&account_id(2), 1_000_000_000);
assert_ok!(Registrar::reserve(signed(1)));
ParaId::from(2000),
test_genesis_head(10),
test_validation_code(10),
));
assert_ok!(Registrar::reserve(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(
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);
// Bid for para 2 directly
Balances::make_free_balance_be(&account_id(2), 1_000_000_000);
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 = [(); 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.clone(), ParaId::from(2000), total));
assert_eq!(Auctions::winning(0), Some(winning));
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 = [(); 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.clone(), 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
Balances::make_free_balance_be(&account_id(1), 1_000_000_000);
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
);
// Now we register the para
assert_ok!(Registrar::reserve(signed(1)));
assert_ok!(Registrar::register(
ParaId::from(2000),
test_genesis_head(10),
test_validation_code(10),
));
// Still can't bid until it is fully onboarded
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
);
// Onboarded on Session 2
run_to_session(2);
// Success
Balances::make_free_balance_be(&account_id(1), 1_000_000_000);
assert_ok!(Auctions::bid(
ParaId::from(2000),
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last slot
));
});
}
#[test]
fn gap_bids_work() {
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));
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(signed(1)));
assert_ok!(Registrar::register(
ParaId::from(2000),
test_genesis_head(10),
test_validation_code(10),
));
assert_ok!(Registrar::reserve(signed(2)));
assert_ok!(Registrar::register(
ParaId::from(2001),
test_genesis_head(10),
test_validation_code(10),
));
// Onboarded on Session 2
run_to_session(2);
// Make bids
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(
ParaId::from(2000),
lease_period_index_start + 0, // First Slot
lease_period_index_start + 0, // Last slot
));
// Slot 4 for 400 from 10
assert_ok!(Auctions::bid(
ParaId::from(2000),
lease_period_index_start + 3, // First Slot
lease_period_index_start + 3, // Last slot
));
// A bid for another para is counted separately.
assert_ok!(Auctions::bid(
ParaId::from(2001),
lease_period_index_start + 1, // First Slot
lease_period_index_start + 1, // Last slot
assert_eq!(Balances::reserved_balance(&account_id(10)), 400 + 555);
// Slot 2 for 800 from 20, overtaking 10's bid
assert_ok!(Auctions::bid(
ParaId::from(2000),
lease_period_index_start + 1, // First Slot
lease_period_index_start + 1, // Last slot
));
// Slot 3 for 200 from 20
assert_ok!(Auctions::bid(
ParaId::from(2000),
lease_period_index_start + 2, // First Slot
lease_period_index_start + 2, // Last slot
));
// Finish the auction
run_to_block(110 + LeaseOffset::get());
// Should have won the lease periods
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(2000)),
// LP 1
// LP 2
// LP 3
// LP 4
// LP 5
// LP 6
// LP 7
);
// Appropriate amount is reserved (largest of the values)
assert_eq!(Balances::reserved_balance(&account_id(10)), 400);
// Appropriate amount is reserved (largest of the values)
assert_eq!(Balances::reserved_balance(&account_id(20)), 800);
// Progress through the leases and note the correct amount of balance is reserved.
add_blocks(300 + LeaseOffset::get());
slots::Leases::<Test>::get(ParaId::from(2000)),
// LP 4
// LP 5
// LP 6
// LP 7
Some((account_id(10), 400))
],
);
// Nothing changed.
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
add_blocks(100);
slots::Leases::<Test>::get(ParaId::from(2000)),
// LP 5
// LP 6
// LP 7
Some((account_id(10), 400))
],
);
// Nothing changed.
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.
add_blocks(100);
slots::Leases::<Test>::get(ParaId::from(2000)),
// --------- 6 -------------- 7 -------
vec![Some((account_id(20), 200)), Some((account_id(10), 400))],
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.
add_blocks(100);
slots::Leases::<Test>::get(ParaId::from(2000)),
// --------- 7 -------
vec![Some((account_id(10), 400))],
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.
add_blocks(100);
assert_eq!(slots::Leases::<Test>::get(ParaId::from(2000)), vec![]);
assert_eq!(Balances::reserved_balance(&account_id(10)), 0);
assert_eq!(Balances::reserved_balance(&account_id(20)), 0);
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
// This test verifies that if a parachain already has won some lease periods, that it cannot bid for
// any of those same lease periods again.
#[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(&account_id(1), 1_000_000_000);
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
// First register a parathread
assert_ok!(Registrar::reserve(signed(1)));
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
assert_ok!(Registrar::register(
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
test_genesis_head(10),
test_validation_code(10),
));
// 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));
// 2 sessions later they are parathreads
run_to_session(2);
// Open a crowdloan for Para 1 for slots 0-3
assert_ok!(Crowdloan::create(
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
lease_period_index_start + 0, // First Slot
lease_period_index_start + 1, // Last Slot
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
None,
));
let fund = Crowdloan::funds(ParaId::from(2000)).unwrap();
let crowdloan_account = Crowdloan::fund_account_id(fund.fund_index);
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
// 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));
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
total += 900 - i;
}
assert!(total > 0);
assert_eq!(Balances::free_balance(&crowdloan_account), total);
// Finish the auction.
run_to_block(starting_block + 110);
// Appropriate Paras should have won slots
assert_eq!(
slots::Leases::<Test>::get(ParaId::from(2000)),
// -- 1 --- 2 --- 3 ------------- 4 ------------------------ 5 -------------
Some((crowdloan_account.clone(), 8855)),
Some((crowdloan_account.clone(), 8855))
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
// Let's start another auction for the same range
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));
// Poke the crowdloan into `NewRaise`
assert_ok!(Crowdloan::poke(signed(1), ParaId::from(2000)));
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
assert_eq!(Crowdloan::new_raise(), vec![ParaId::from(2000)]);
// Beginning of ending block.
run_to_block(starting_block + 100);
// Bids cannot be made which intersect
assert_noop!(
Auctions::bid(
Origin::signed(crowdloan_account.clone()),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
2,
lease_period_index_start + 0,
lease_period_index_start + 1,
100,
),
AuctionsError::<Test>::AlreadyLeasedOut,
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
assert_noop!(
Auctions::bid(
Origin::signed(crowdloan_account.clone()),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
2,
lease_period_index_start + 1,
lease_period_index_start + 2,
100,
),
AuctionsError::<Test>::AlreadyLeasedOut,
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
assert_noop!(
Auctions::bid(
Origin::signed(crowdloan_account.clone()),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
2,
lease_period_index_start - 1,
lease_period_index_start + 0,
100,
),
AuctionsError::<Test>::AlreadyLeasedOut,
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
assert_noop!(
Auctions::bid(
Origin::signed(crowdloan_account.clone()),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
2,
lease_period_index_start + 0,
lease_period_index_start + 0,
100,
),
AuctionsError::<Test>::AlreadyLeasedOut,
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
assert_noop!(
Auctions::bid(
Origin::signed(crowdloan_account.clone()),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
2,
lease_period_index_start + 1,
lease_period_index_start + 1,
100,
),
AuctionsError::<Test>::AlreadyLeasedOut,
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
assert_noop!(
Auctions::bid(
Origin::signed(crowdloan_account.clone()),
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
ParaId::from(2000),
2,
lease_period_index_start - 1,
lease_period_index_start + 5,
100,
),
AuctionsError::<Test>::AlreadyLeasedOut,
![Shawn Tabrizi Shawn Tabrizi's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
Shawn Tabrizi
committed
);
// Will work when not overlapping
Origin::signed(crowdloan_account.clone()),
ParaId::from(2000),
2,
lease_period_index_start + 2,
lease_period_index_start + 3,
100,
));