Newer
Older
assert_eq!(TestAuctioneer::is_ending(11), None);
});
}
#[test]
fn create_works() {
new_test_ext().execute_with(|| {
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, None));
// This is what the initial `fund_info` should look like
let fund_info = FundInfo {
verifier: None,
deposit: 1,
raised: 0,
// 5 blocks length + 3 block ending period + 1 starting block
end: 9,
cap: 1000,
last_contribution: LastContribution::Never,
first_period: 1,
last_period: 4,
assert_eq!(Crowdloan::funds(para), Some(fund_info));
// User has deposit removed from their free balance
assert_eq!(Balances::free_balance(1), 999);
// Deposit is placed in reserved
assert_eq!(Balances::reserved_balance(1), 1);
// No new raise until first contribution
let empty: Vec<ParaId> = Vec::new();
assert_eq!(Crowdloan::new_raise(), empty);
});
}
#[test]
fn create_with_verifier_works() {
new_test_ext().execute_with(|| {
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
// Now try to create a crowdloan campaign
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, Some(pubkey.clone())));
// This is what the initial `fund_info` should look like
let fund_info = FundInfo {
deposit: 1,
raised: 0,
// 5 blocks length + 3 block ending period + 1 starting block
end: 9,
cap: 1000,
last_contribution: LastContribution::Never,
first_period: 1,
last_period: 4,
assert_eq!(Crowdloan::funds(ParaId::from(0)), Some(fund_info));
// User has deposit removed from their free balance
assert_eq!(Balances::free_balance(1), 999);
// Deposit is placed in reserved
assert_eq!(Balances::reserved_balance(1), 1);
// No new raise until first contribution
let empty: Vec<ParaId> = Vec::new();
});
}
#[test]
fn create_handles_basic_errors() {
new_test_ext().execute_with(|| {
// Now try to create a crowdloan campaign
let para = new_para();
let e = Error::<Test>::InvalidParaId;
assert_noop!(Crowdloan::create(Origin::signed(1), 1.into(), 1000, 1, 4, 9, None), e);
// Cannot create a crowdloan with bad lease periods
let e = Error::<Test>::LastPeriodBeforeFirstPeriod;
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 4, 1, 9, None), e);
let e = Error::<Test>::LastPeriodTooFarInFuture;
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 9, 9, None), e);
// Cannot create a crowdloan without some deposit funds
assert_ok!(TestRegistrar::<Test>::register(1337, ParaId::from(1234), Default::default(), Default::default()));
let e = BalancesError::<Test, _>::InsufficientBalance;
assert_noop!(Crowdloan::create(Origin::signed(1337), ParaId::from(1234), 1000, 1, 3, 9, None), e);
// Cannot create a crowdloan with nonsense end date
// This crowdloan would end in lease period 2, but is bidding for some slot that starts in lease period 1.
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 41, None), Error::<Test>::EndTooFarInFuture);
});
}
#[test]
fn contribute_works() {
new_test_ext().execute_with(|| {
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, None));
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 0);
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 49, None));
// User 1 has spent some funds to do this, transfer fees **are** taken
// 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!(Crowdloan::new_raise(), vec![para]);
let fund = Crowdloan::funds(para).unwrap();
// Last contribution time recorded
assert_eq!(fund.last_contribution, LastContribution::PreEnding(0));
assert_eq!(fund.raised, 49);
});
}
#[test]
fn contribute_with_verifier_works() {
new_test_ext().execute_with(|| {
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
// Set up a crowdloan
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, Some(pubkey.clone())));
// No contributions yet
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 0);
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::InvalidSignature);
let payload = (0u32, 1u64, 0u64, 49u64);
let valid_signature = crypto::create_ed25519_signature(&payload.encode(), pubkey.clone());
let invalid_signature = MultiSignature::default();
// Invalid signature
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, Some(invalid_signature)), Error::<Test>::InvalidSignature);
// Valid signature wrong parameter
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 50, Some(valid_signature.clone())), Error::<Test>::InvalidSignature);
assert_noop!(Crowdloan::contribute(Origin::signed(2), para, 49, Some(valid_signature.clone())), Error::<Test>::InvalidSignature);
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 49, Some(valid_signature.clone())));
// Reuse valid signature
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, Some(valid_signature)), Error::<Test>::InvalidSignature);
let payload_2 = (0u32, 1u64, 49u64, 10u64);
let valid_signature_2 = crypto::create_ed25519_signature(&payload_2.encode(), pubkey);
// New valid signature
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);
// Contribution amount is correct
let fund = Crowdloan::funds(para).unwrap();
assert_eq!(fund.raised, 59);
});
}
#[test]
fn contribute_handles_basic_errors() {
new_test_ext().execute_with(|| {
// Cannot contribute to non-existing fund
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::InvalidParaId);
// Cannot contribute below minimum contribution
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 9, None), Error::<Test>::ContributionTooSmall);
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, None));
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 101, None));
// Cannot contribute past the limit
assert_noop!(Crowdloan::contribute(Origin::signed(2), para, 900, None), Error::<Test>::CapExceeded);
// Move past end date
run_to_block(10);
// Cannot contribute to ended fund
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::ContributionPeriodOver);
// If a crowdloan has already won, it should not allow contributions.
let para_2 = new_para();
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);
set_winner(para_2, crowdloan_account, true);
assert_noop!(Crowdloan::contribute(Origin::signed(1), para_2, 49, None), Error::<Test>::BidOrLeaseActive);
// Move past lease period 1, should not be allowed to have further contributions with a crowdloan
// that has starting period 1.
let para_3 = new_para();
assert_ok!(Crowdloan::create(Origin::signed(1), para_3, 1000, 1, 4, 40, None));
run_to_block(40);
assert_eq!(TestAuctioneer::lease_period_index(), 2);
assert_noop!(Crowdloan::contribute(Origin::signed(1), para_3, 49, None), Error::<Test>::ContributionPeriodOver);
new_test_ext().execute_with(|| {
let first_period = 1;
let last_period = 4;
assert_ok!(TestAuctioneer::new_auction(5, 0));
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, first_period, last_period, 9, None));
let bidder = Crowdloan::fund_account_id(para);
run_to_block(1);
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 100, None));
run_to_block(3);
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 150, None));
run_to_block(5);
assert_ok!(Crowdloan::contribute(Origin::signed(4), para, 200, None));
run_to_block(8);
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 250, None));
BidPlaced { height: 5, amount: 250, bidder, para, first_period, last_period },
BidPlaced { height: 6, amount: 450, bidder, para, first_period, last_period },
BidPlaced { height: 9, amount: 700, bidder, para, first_period, last_period },
new_test_ext().execute_with(|| {
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None));
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 100, None));
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 50, None));
let account_id = Crowdloan::fund_account_id(para);
// 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.
assert_eq!(Balances::free_balance(&account_id), 150);
assert_eq!(Balances::free_balance(2), 1900);
assert_eq!(Balances::free_balance(3), 2950);
assert_ok!(Crowdloan::withdraw(Origin::signed(2), 2, para));
assert_eq!(Balances::free_balance(&account_id), 50);
assert_eq!(Balances::free_balance(2), 2000);
assert_ok!(Crowdloan::withdraw(Origin::signed(2), 3, para));
assert_eq!(Balances::free_balance(&account_id), 0);
assert_eq!(Balances::free_balance(3), 3000);
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
#[test]
fn withdraw_cannot_be_griefed() {
new_test_ext().execute_with(|| {
let para = new_para();
// 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);
// user sends the crowdloan funds trying to make an accounting error
assert_ok!(Balances::transfer(Origin::signed(1), account_id, 10));
// overfunded now
assert_eq!(Balances::free_balance(&account_id), 110);
assert_eq!(Balances::free_balance(2), 1900);
assert_ok!(Crowdloan::withdraw(Origin::signed(2), 2, para));
assert_eq!(Balances::free_balance(2), 2000);
// Some funds are left over
assert_eq!(Balances::free_balance(&account_id), 10);
// They wil be left in the account at the end
assert_ok!(Crowdloan::dissolve(Origin::signed(1), para));
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
assert_eq!(Balances::free_balance(&account_id), 10);
});
}
#[test]
fn refund_works() {
new_test_ext().execute_with(|| {
let para = new_para();
let account_id = Crowdloan::fund_account_id(para);
// Set up a crowdloan ending on 9
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None));
// Make some contributions
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 100, None));
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 200, None));
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 300, None));
assert_eq!(Balances::free_balance(account_id), 600);
// Can't refund before the crowdloan it has ended
assert_noop!(
Crowdloan::refund(Origin::signed(1337), para),
Error::<Test>::FundNotEnded,
);
// Move to the end of the crowdloan
run_to_block(10);
assert_ok!(Crowdloan::refund(Origin::signed(1337), para));
// Funds are returned
assert_eq!(Balances::free_balance(account_id), 0);
// 1 deposit for the crowdloan which hasn't dissolved yet.
assert_eq!(Balances::free_balance(1), 1000 - 1);
assert_eq!(Balances::free_balance(2), 2000);
assert_eq!(Balances::free_balance(3), 3000);
fn multiple_refund_works() {
new_test_ext().execute_with(|| {
let account_id = Crowdloan::fund_account_id(para);
// Set up a crowdloan ending on 9
assert_ok!(Crowdloan::create(Origin::signed(1), para, 100000, 1, 1, 9, None));
// Make more contributions than our limit
for i in 1 ..= RemoveKeysLimit::get() * 2 {
Balances::make_free_balance_be(&i.into(), (1000 * i).into());
assert_ok!(Crowdloan::contribute(Origin::signed(i.into()), para, (i * 100).into(), None));
}
assert_eq!(Balances::free_balance(account_id), 21000);
// Move to the end of the crowdloan
run_to_block(10);
assert_ok!(Crowdloan::refund(Origin::signed(1337), para));
assert_eq!(last_event(), super::Event::<Test>::PartiallyRefunded(para).into());
// Funds still left over
assert!(!Balances::free_balance(account_id).is_zero());
// Call again
assert_ok!(Crowdloan::refund(Origin::signed(1337), para));
assert_eq!(last_event(), super::Event::<Test>::AllRefunded(para).into());
// Funds are returned
assert_eq!(Balances::free_balance(account_id), 0);
// 1 deposit for the crowdloan which hasn't dissolved yet.
for i in 1 ..= RemoveKeysLimit::get() * 2 {
assert_eq!(Balances::free_balance(&i.into()), i as u64 * 1000);
}
});
}
#[test]
fn refund_and_dissolve_works() {
new_test_ext().execute_with(|| {
let para = new_para();
let issuance = Balances::total_issuance();
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None));
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 100, None));
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 50, None));
// All funds are refunded
assert_ok!(Crowdloan::refund(Origin::signed(2), para));
// Now that `fund.raised` is zero, it can be dissolved.
assert_ok!(Crowdloan::dissolve(Origin::signed(1), para));
assert_eq!(Balances::free_balance(1), 1000);
assert_eq!(Balances::free_balance(2), 2000);
assert_eq!(Balances::free_balance(3), 3000);
assert_eq!(Balances::total_issuance(), issuance);
fn dissolve_works() {
new_test_ext().execute_with(|| {
let para = new_para();
let issuance = Balances::total_issuance();
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None));
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 100, None));
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 50, None));
// Can't dissolve before it ends
assert_noop!(Crowdloan::dissolve(Origin::signed(1), para), Error::<Test>::NotReadyToDissolve);
set_winner(para, 1, true);
// Can't dissolve when it won.
assert_noop!(Crowdloan::dissolve(Origin::signed(1), para), Error::<Test>::NotReadyToDissolve);
set_winner(para, 1, false);
// Can't dissolve while it still has user funds
assert_noop!(Crowdloan::dissolve(Origin::signed(1), para), Error::<Test>::NotReadyToDissolve);
// All funds are refunded
assert_ok!(Crowdloan::refund(Origin::signed(2), para));
// Now that `fund.raised` is zero, it can be dissolved.
assert_ok!(Crowdloan::dissolve(Origin::signed(1), para));
assert_eq!(Balances::free_balance(1), 1000);
assert_eq!(Balances::free_balance(2), 2000);
assert_eq!(Balances::free_balance(3), 3000);
assert_eq!(Balances::total_issuance(), issuance);
fn withdraw_from_finished_works() {
new_test_ext().execute_with(|| {
let para = new_para();
let account_id = Crowdloan::fund_account_id(para);
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 1, 9, None));
// Fund crowdloans.
assert_ok!(Crowdloan::contribute(Origin::signed(2), para, 100, None));
assert_ok!(Crowdloan::contribute(Origin::signed(3), para, 50, None));
// simulate the reserving of para's funds. this actually happens in the Slots pallet.
assert_ok!(Balances::reserve(&account_id, 150));
run_to_block(19);
assert_noop!(Crowdloan::withdraw(Origin::signed(2), 2, para), Error::<Test>::BidOrLeaseActive);
run_to_block(20);
// simulate the unreserving of para's funds, now that the lease expired. this actually
// happens in the Slots pallet.
Balances::unreserve(&account_id, 150);
// para has no reserved funds, indicating it did ot win the auction.
assert_eq!(Balances::reserved_balance(&account_id), 0);
// but there's still the funds in its balance.
assert_eq!(Balances::free_balance(&account_id), 150);
assert_eq!(Balances::free_balance(2), 1900);
assert_eq!(Balances::free_balance(3), 2950);
assert_ok!(Crowdloan::withdraw(Origin::signed(2), 2, para));
assert_eq!(Balances::free_balance(&account_id), 50);
assert_ok!(Crowdloan::withdraw(Origin::signed(2), 3, para));
assert_eq!(Balances::free_balance(&account_id), 0);
new_test_ext().execute_with(|| {
let para_1 = new_para();
let para_2 = new_para();
// Set up crowdloans
assert_ok!(Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None));
assert_ok!(Crowdloan::create(Origin::signed(1), para_2, 1000, 1, 1, 9, None));
// Different contributions
assert_ok!(Crowdloan::contribute(Origin::signed(2), para_1, 100, None));
assert_ok!(Crowdloan::contribute(Origin::signed(3), para_2, 50, None));
// Original state
assert_eq!(Funds::<Test>::get(para_1).unwrap().raised, 100);
assert_eq!(Funds::<Test>::get(para_2).unwrap().raised, 50);
// Swap
Crowdloan::on_swap(para_1, para_2);
// Final state
assert_eq!(Funds::<Test>::get(para_2).unwrap().raised, 100);
assert_eq!(Funds::<Test>::get(para_1).unwrap().raised, 50);
fn cannot_create_fund_when_already_active() {
new_test_ext().execute_with(|| {
assert_ok!(Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None));
// Cannot create a fund again
assert_noop!(
Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None),
Error::<Test>::FundNotEnded,
);
#[test]
fn edit_works() {
new_test_ext().execute_with(|| {
let para_1 = new_para();
assert_ok!(Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None));
assert_ok!(Crowdloan::contribute(Origin::signed(2), para_1, 100, None));
let old_crowdloan = Crowdloan::funds(para_1).unwrap();
assert_ok!(Crowdloan::edit(Origin::root(), para_1, 1234, 2, 3, 4, None));
let new_crowdloan = Crowdloan::funds(para_1).unwrap();
// Some things stay the same
assert_eq!(old_crowdloan.depositor, new_crowdloan.depositor);
assert_eq!(old_crowdloan.deposit, new_crowdloan.deposit);
assert_eq!(old_crowdloan.raised, new_crowdloan.raised);
// Some things change
assert!(old_crowdloan.cap != new_crowdloan.cap);
assert!(old_crowdloan.first_period != new_crowdloan.first_period);
assert!(old_crowdloan.last_period != new_crowdloan.last_period);
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
#[test]
fn add_memo_works() {
new_test_ext().execute_with(|| {
let para_1 = new_para();
assert_ok!(Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None));
// Cant add a memo before you have contributed.
assert_noop!(
Crowdloan::add_memo(Origin::signed(1), para_1, b"hello, world".to_vec()),
Error::<Test>::NoContributions,
);
// Make a contribution. Initially no memo.
assert_ok!(Crowdloan::contribute(Origin::signed(1), para_1, 100, None));
assert_eq!(Crowdloan::contribution_get(0u32, &1), (100, vec![]));
// Can't place a memo that is too large.
assert_noop!(
Crowdloan::add_memo(Origin::signed(1), para_1, vec![123; 123]),
Error::<Test>::MemoTooLarge,
);
// Adding a memo to an existing contribution works
assert_ok!(Crowdloan::add_memo(Origin::signed(1), para_1, b"hello, world".to_vec()));
assert_eq!(Crowdloan::contribution_get(0u32, &1), (100, b"hello, world".to_vec()));
// Can contribute again and data persists
assert_ok!(Crowdloan::contribute(Origin::signed(1), para_1, 100, None));
assert_eq!(Crowdloan::contribution_get(0u32, &1), (200, b"hello, world".to_vec()));
});
}
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
#[test]
fn poke_works() {
new_test_ext().execute_with(|| {
let para_1 = new_para();
assert_ok!(TestAuctioneer::new_auction(5, 0));
assert_ok!(Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None));
// Should fail when no contributions.
assert_noop!(
Crowdloan::poke(Origin::signed(1), para_1),
Error::<Test>::NoContributions
);
assert_ok!(Crowdloan::contribute(Origin::signed(2), para_1, 100, None));
run_to_block(6);
assert_ok!(Crowdloan::poke(Origin::signed(1), para_1));
assert_eq!(Crowdloan::new_raise(), vec![para_1]);
assert_noop!(
Crowdloan::poke(Origin::signed(1), para_1),
Error::<Test>::AlreadyInNewRaise
);
});
}
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking {
use super::{*, Pallet as Crowdloan};
use frame_system::RawOrigin;
use frame_support::{
assert_ok,
traits::OnInitialize,
};
use sp_runtime::traits::{Bounded, CheckedSub};
use frame_benchmarking::{benchmarks, whitelisted_caller, account, impl_benchmark_test_suite};
fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
Shaun Wang
committed
let events = frame_system::Pallet::<T>::events();
let system_event: <T as frame_system::Config>::Event = generic_event.into();
// compare to the last event record
let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event);
}
fn create_fund<T: Config>(id: u32, end: T::BlockNumber) -> ParaId {
let lease_period_index = T::Auctioneer::lease_period_index();
let first_period = lease_period_index;
let last_period = lease_period_index + ((SlotRange::LEASE_PERIODS_PER_SLOT as u32) - 1).into();
let caller = account("fund_creator", id, 0);
CurrencyOf::<T>::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
// Assume ed25519 is most complex signature format
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
let head_data = T::Registrar::worst_head_data();
let validation_code = T::Registrar::worst_validation_code();
assert_ok!(T::Registrar::register(caller.clone(), para_id, head_data, validation_code));
T::Registrar::execute_pending_transitions();
assert_ok!(Crowdloan::<T>::create(
RawOrigin::Signed(caller).into(),
para_id,
cap,
first_period,
last_period,
end,
Some(pubkey)
));
para_id
fn contribute_fund<T: Config>(who: &T::AccountId, index: ParaId) {
CurrencyOf::<T>::make_free_balance_be(&who, BalanceOf::<T>::max_value());
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
let payload = (index, &who, BalanceOf::<T>::default(), value);
let sig = crypto::create_ed25519_signature(&payload.encode(), pubkey);
assert_ok!(Crowdloan::<T>::contribute(RawOrigin::Signed(who.clone()).into(), index, value, Some(sig)));
let first_period = 0u32.into();
let last_period = 3u32.into();
let end = T::Auctioneer::lease_period();
let caller: T::AccountId = whitelisted_caller();
let head_data = T::Registrar::worst_head_data();
let validation_code = T::Registrar::worst_validation_code();
let verifier = account("verifier", 0, 0);
CurrencyOf::<T>::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
T::Registrar::register(caller.clone(), para_id, head_data, validation_code)?;
T::Registrar::execute_pending_transitions();
}: _(RawOrigin::Signed(caller), para_id, cap, first_period, last_period, end, Some(verifier))
assert_last_event::<T>(Event::<T>::Created(para_id).into())
}
// Contribute has two arms: PreEnding and Ending, but both are equal complexity.
contribute {
let fund_index = create_fund::<T>(1, 100u32.into());
let caller: T::AccountId = whitelisted_caller();
let contribution = T::MinContribution::get();
CurrencyOf::<T>::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
assert!(NewRaise::<T>::get().is_empty());
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
let payload = (fund_index, &caller, BalanceOf::<T>::default(), contribution);
let sig = crypto::create_ed25519_signature(&payload.encode(), pubkey);
}: _(RawOrigin::Signed(caller.clone()), fund_index, contribution, Some(sig))
verify {
// NewRaise is appended to, so we don't need to fill it up for worst case scenario.
assert!(!NewRaise::<T>::get().is_empty());
assert_last_event::<T>(Event::<T>::Contributed(caller, fund_index, contribution).into());
let fund_index = create_fund::<T>(1337, 100u32.into());
let caller: T::AccountId = whitelisted_caller();
let contributor = account("contributor", 0, 0);
contribute_fund::<T>(&contributor, fund_index);
Shaun Wang
committed
frame_system::Pallet::<T>::set_block_number(200u32.into());
}: _(RawOrigin::Signed(caller), contributor.clone(), fund_index)
verify {
assert_last_event::<T>(Event::<T>::Withdrew(contributor, fund_index, T::MinContribution::get()).into());
// Worst case: Refund removes `RemoveKeysLimit` keys, and is fully refunded.
refund {
let k in 0 .. T::RemoveKeysLimit::get();
let fund_index = create_fund::<T>(1337, 100u32.into());
// Dissolve will remove at most `RemoveKeysLimit` at once.
contribute_fund::<T>(&account("contributor", i, 0), fund_index);
}
let caller: T::AccountId = whitelisted_caller();
frame_system::Pallet::<T>::set_block_number(200u32.into());
}: _(RawOrigin::Signed(caller), fund_index)
verify {
assert_last_event::<T>(Event::<T>::AllRefunded(fund_index).into());
dissolve {
let fund_index = create_fund::<T>(1337, 100u32.into());
let caller: T::AccountId = whitelisted_caller();
Shaun Wang
committed
frame_system::Pallet::<T>::set_block_number(T::BlockNumber::max_value());
}: _(RawOrigin::Signed(caller.clone()), fund_index)
verify {
assert_last_event::<T>(Event::<T>::Dissolved(fund_index).into());
edit {
let para_id = ParaId::from(1);
let cap = BalanceOf::<T>::max_value();
let first_period = 0u32.into();
let last_period = 3u32.into();
let end = T::Auctioneer::lease_period();
let caller: T::AccountId = whitelisted_caller();
let head_data = T::Registrar::worst_head_data();
let validation_code = T::Registrar::worst_validation_code();
let verifier: MultiSigner = account("verifier", 0, 0);
CurrencyOf::<T>::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
T::Registrar::register(caller.clone(), para_id, head_data, validation_code)?;
T::Registrar::execute_pending_transitions();
Crowdloan::<T>::create(
RawOrigin::Signed(caller).into(),
para_id, cap, first_period, last_period, end, Some(verifier.clone()),
)?;
// Doesn't matter what we edit to, so use the same values.
}: _(RawOrigin::Root, para_id, cap, first_period, last_period, end, Some(verifier))
assert_last_event::<T>(Event::<T>::Edited(para_id).into())
add_memo {
let fund_index = create_fund::<T>(1, 100u32.into());
let caller: T::AccountId = whitelisted_caller();
contribute_fund::<T>(&caller, fund_index);
let worst_memo = vec![42; T::MaxMemoLength::get().into()];
}: _(RawOrigin::Signed(caller.clone()), fund_index, worst_memo.clone())
verify {
let fund = Funds::<T>::get(fund_index).expect("fund was created...");
assert_eq!(
Crowdloan::<T>::contribution_get(fund.trie_index, &caller),
(T::MinContribution::get(), worst_memo),
);
}
poke {
let fund_index = create_fund::<T>(1, 100u32.into());
let caller: T::AccountId = whitelisted_caller();
contribute_fund::<T>(&caller, fund_index);
NewRaise::<T>::kill();
assert!(NewRaise::<T>::get().is_empty());
}: _(RawOrigin::Signed(caller), fund_index)
verify {
assert!(!NewRaise::<T>::get().is_empty());
assert_last_event::<T>(Event::<T>::AddedToNewRaise(fund_index).into())
// Worst case scenario: N funds are all in the `NewRaise` list, we are
// in the beginning of the ending period, and each fund outbids the next
on_initialize {
// We test the complexity over different number of new raise
let n in 2 .. 100;
let end_block: T::BlockNumber = 100u32.into();
let pubkey = crypto::create_ed25519_pubkey(b"//verifier".to_vec());
let fund_index = create_fund::<T>(i, end_block);
let contributor: T::AccountId = account("contributor", i, 0);
let contribution = T::MinContribution::get() * (i + 1).into();
let payload = (fund_index, &contributor, BalanceOf::<T>::default(), contribution);
let sig = crypto::create_ed25519_signature(&payload.encode(), pubkey.clone());
CurrencyOf::<T>::make_free_balance_be(&contributor, BalanceOf::<T>::max_value());
Crowdloan::<T>::contribute(RawOrigin::Signed(contributor).into(), fund_index, contribution, Some(sig))?;
let lease_period_index = T::Auctioneer::lease_period_index();
let duration = end_block
Shaun Wang
committed
.checked_sub(&frame_system::Pallet::<T>::block_number())
.ok_or("duration of auction less than zero")?;
T::Auctioneer::new_auction(duration, lease_period_index)?;
assert_eq!(T::Auctioneer::is_ending(end_block), Some(0u32.into()));
assert_eq!(NewRaise::<T>::get().len(), n as usize);
let old_endings_count = EndingsCount::<T>::get();
}: {
Crowdloan::<T>::on_initialize(end_block);
} verify {
assert_eq!(EndingsCount::<T>::get(), old_endings_count + 1);
assert_last_event::<T>(Event::<T>::HandleBidResult((n - 1).into(), Ok(())).into());
impl_benchmark_test_suite!(
Crowdloan,
crate::integration_tests::new_test_ext(),
crate::integration_tests::Test,
);