Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow early refund of slot deposit #1749

Closed
wants to merge 67 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
3ce96b5
allow early refund of slot deposit
Ank4n Sep 29, 2023
c8bf558
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Sep 29, 2023
c899393
fix extrinsic name
Ank4n Sep 29, 2023
1bd3a4c
notes
Ank4n Sep 29, 2023
7770df6
fixme note
Ank4n Sep 29, 2023
3df7e27
notes to add reserved balance in state
Ank4n Sep 29, 2023
2231764
more fixme
Ank4n Sep 29, 2023
4a6a6ba
some tests are failing
Ank4n Sep 29, 2023
f5a253e
fix updating of unreserve
Ank4n Sep 29, 2023
8a3980c
all existing tests pass
Ank4n Sep 29, 2023
63379bb
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Sep 29, 2023
7cdc7c3
doc comments
Ank4n Sep 29, 2023
6c2387c
set Earliest refund period to 0 in runtimes
Ank4n Sep 29, 2023
2e072ce
fix import
Ank4n Sep 29, 2023
13c3b80
fmt
Ank4n Sep 29, 2023
e5cf1d9
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Sep 29, 2023
3d2af1a
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Oct 1, 2023
146a9ae
only allow para managers to do it
Ank4n Oct 2, 2023
3beceeb
version storage for crowdloan pallet
Ank4n Oct 2, 2023
b7c2792
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Oct 2, 2023
883585d
migration placeholder
Ank4n Oct 2, 2023
28fba4d
quick migration, need to review it again
Ank4n Oct 2, 2023
a3615cb
Update migration.rs
Ank4n Oct 4, 2023
95d3768
Merge branch 'master' into ankan/crowdloan-rebid
kianenigma Oct 22, 2023
2ff9893
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Oct 25, 2023
3f31e95
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Oct 25, 2023
521dba1
doc linking fix
Ank4n Oct 25, 2023
8d22ef5
test for early lease refund
Ank4n Oct 25, 2023
4980e48
verify leases remaining
Ank4n Oct 25, 2023
92d37be
add integration test
Ank4n Oct 26, 2023
dae72fc
fmt
Ank4n Oct 26, 2023
c7a89a7
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Oct 26, 2023
8863d17
bench of early lease refund
Ank4n Oct 26, 2023
33b351c
doc fix
Ank4n Oct 26, 2023
ebedb85
add migrations to westend and rococo, and set earliest refund period …
Ank4n Oct 26, 2023
0e0ca40
migration weights
Ank4n Oct 26, 2023
1c4e4a4
fmt
Ank4n Oct 26, 2023
87fefd6
fix weights
Ank4n Oct 26, 2023
cd92e1a
Merge branch 'master' of https://github.com/paritytech/polkadot-sdk i…
Oct 26, 2023
10bf8b9
".git/.scripts/commands/bench-all/bench-all.sh" --runtime=westend --t…
Oct 27, 2023
ac1153a
pr feedbacks
Ank4n Oct 27, 2023
2bdbaca
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Oct 30, 2023
1d7c6a9
".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtim…
Oct 30, 2023
177b625
do not mutate reserve amount if reserve fails
Ank4n Oct 30, 2023
d0a850d
update reserved amount only with amount that is unreserved
Ank4n Oct 30, 2023
6c70567
refactor based on PR feedback
Ank4n Oct 30, 2023
c7d0096
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 15, 2023
befa2e9
store reserved amount as well as period count
Ank4n Nov 16, 2023
5291d92
check that para has leased out enough leases
Ank4n Nov 16, 2023
d6acce8
remove early lease period conditions
Ank4n Nov 16, 2023
a4381d4
fix doc and format
Ank4n Nov 16, 2023
c76077d
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 19, 2023
a6f3cbe
fix migration
Ank4n Nov 19, 2023
af0f9f1
fix np path
Ank4n Nov 19, 2023
4a5b0fa
extend integration test with parachain applying for a new crowdloan a…
Ank4n Nov 19, 2023
962de0e
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 19, 2023
e1eeb21
rename
Ank4n Nov 19, 2023
ee5a04b
pr feedbacks
Ank4n Nov 19, 2023
8f98b65
fix rust doc
Ank4n Nov 20, 2023
4297d00
pr feedbacks and test for disabling early lease
Ank4n Nov 21, 2023
4e279d5
allow parachain to call early lease refund via xcm
Ank4n Nov 21, 2023
294b0c6
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 21, 2023
6447b5b
rename aggregated runtime origin to avoid conflict with system runtim…
Ank4n Nov 21, 2023
427aa4d
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 21, 2023
4d6bc2f
pr feedback
Ank4n Nov 22, 2023
8f13a13
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 22, 2023
a215db5
Merge branch 'master' into ankan/crowdloan-rebid
Ank4n Nov 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions polkadot/runtime/common/src/assigned_slots/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ mod tests {
Parachains: parachains_paras::{Pallet, Call, Storage, Config<T>, Event},
Slots: slots::{Pallet, Call, Storage, Event<T>},
AssignedSlots: assigned_slots::{Pallet, Call, Storage, Event<T>},
ParachainsOrigin: runtime_parachains::origin::{Pallet, Origin},
}
);

Expand Down Expand Up @@ -745,17 +746,22 @@ mod tests {

impl parachains_shared::Config for Test {}

impl runtime_parachains::origin::Config for Test {}

parameter_types! {
pub const LeasePeriod: BlockNumber = 3;
pub const MinLeasePeriodsForEarlyRefund: BlockNumber = 2;
pub static LeaseOffset: BlockNumber = 0;
pub const ParaDeposit: u64 = 1;
}

impl slots::Config for Test {
type RuntimeEvent = RuntimeEvent;
type ParachainOrigin = RuntimeOrigin;
type Currency = Balances;
type Registrar = TestRegistrar<Test>;
type LeasePeriod = LeasePeriod;
type MinLeasePeriodsForEarlyRefund = MinLeasePeriodsForEarlyRefund;
type LeaseOffset = LeaseOffset;
type ForceOrigin = EnsureRoot<Self::AccountId>;
type WeightInfo = crate::slots::TestWeightInfo;
Expand Down
195 changes: 194 additions & 1 deletion polkadot/runtime/common/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ where
type OverarchingCall = RuntimeCall;
}

use crate::{auctions::Error as AuctionsError, crowdloan::Error as CrowdloanError};
use crate::{
auctions::Error as AuctionsError, crowdloan::Error as CrowdloanError,
slots::Error as SlotsError,
};

parameter_types! {
pub const BlockHashCount: u32 = 250;
Expand Down Expand Up @@ -246,14 +249,17 @@ impl auctions::Config for Test {

parameter_types! {
pub const LeasePeriod: BlockNumber = 100;
pub const MinLeasePeriodsForEarlyRefund: BlockNumber = 2;
pub static LeaseOffset: BlockNumber = 5;
}

impl slots::Config for Test {
type RuntimeEvent = RuntimeEvent;
type ParachainOrigin = RuntimeOrigin;
type Currency = Balances;
type Registrar = Registrar;
type LeasePeriod = LeasePeriod;
type MinLeasePeriodsForEarlyRefund = MinLeasePeriodsForEarlyRefund;
type LeaseOffset = LeaseOffset;
type ForceOrigin = EnsureRoot<AccountId>;
type WeightInfo = crate::slots::TestWeightInfo;
Expand Down Expand Up @@ -1725,3 +1731,190 @@ fn cant_bid_on_existing_lease_periods() {
));
});
}

#[test]
fn early_crowdloan_dissolve() {
// This test will refund a lease deposit before it ends and subsequently dissolve the crowdloan.
new_test_ext().execute_with(|| {
assert!(System::block_number().is_one()); /* So events are emitted */

const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);

// User 1 will own para
Balances::make_free_balance_be(&account_id(1), 1_000_000_000);

// Register on-demand parachain
let para_id = ParaId::from(2000);
let validation_code_storage_size: usize = 10;
let genesis_storage_size: usize = 10;
let validation_code = test_validation_code(validation_code_storage_size);
// deposit for para registration
let expected_deposit_para_registration: Balance = ParaDeposit::get() +
DataDepositPerByte::get() * validation_code_storage_size as Balance +
DataDepositPerByte::get() * genesis_storage_size as Balance;

assert_ok!(Registrar::reserve(signed(1)));
assert_ok!(Registrar::register(
signed(1),
para_id,
test_genesis_head(genesis_storage_size),
validation_code.clone(),
));
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);

// Para 2000 should be onboarding
assert_eq!(Paras::lifecycle(para_id), 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 2000 is an on-demand parachain
run_to_session(START_SESSION_INDEX + 2);
assert_eq!(Paras::lifecycle(para_id), Some(ParaLifecycle::Parathread));

// Open a crowdloan for Para 1 for slots 0-3
assert_ok!(Crowdloan::create(
signed(1),
para_id,
1_000_000, // Cap
lease_period_index_start + 0, // First Slot
lease_period_index_start + 3, // Last Slot
200, // Block End
None,
));
let fund = Crowdloan::funds(para_id).unwrap();
let crowdloan_account = Crowdloan::fund_account_id(fund.fund_index);

// Bunch of contributions
let mut total = 0;
for i in 10..20 {
Balances::make_free_balance_be(&account_id(i), 1_000_000_000);
assert_ok!(Crowdloan::contribute(signed(i), para_id, 900 - i, None));
total += 900 - i;
}
// Go to end of auction where everyone won their slots
run_to_block(200);

assert_eq!(
Balances::reserved_balance(&account_id(1)),
expected_deposit_para_registration + SubmissionDeposit::get()
);
// crowdloan fund is reserved
assert_eq!(Balances::reserved_balance(&crowdloan_account), total);
// Crowdloan is appropriately set
assert!(Crowdloan::funds(para_id).is_some());

// 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(para_id).is_empty());

// 2 sessions later it is a parachain
run_to_block(lease_start_block + 20);
assert_eq!(Paras::lifecycle(para_id), Some(ParaLifecycle::Parachain));

// lease is active and not near end
assert_noop!(
Slots::early_lease_refund(signed(1), para_id),
SlotsError::<Test>::PreconditionNotMet
);

// Cant dissolve yet
assert_noop!(
Crowdloan::dissolve(signed(1), para_id),
CrowdloanError::<Test>::NotReadyToDissolve
);

let lease_end_block = 8 * LeasePeriod::get() + LeaseOffset::get();
// early refund can be applied from the 1st block in the last lease period.
let early_refund_start_block = lease_end_block - LeasePeriod::get();

// try early refund before the start of the last lease period
run_to_block(early_refund_start_block - 1);
assert_noop!(
Slots::early_lease_refund(signed(1), para_id),
SlotsError::<Test>::PreconditionNotMet
);

run_to_block(early_refund_start_block);
// now early refund should work
assert_ok!(Slots::early_lease_refund(signed(1), para_id));

// Withdraw of contributions works
assert_eq!(Balances::free_balance(&crowdloan_account), total);
for i in 10..20 {
assert_ok!(Crowdloan::withdraw(signed(i), account_id(i), para_id));
}

assert_eq!(Balances::free_balance(&crowdloan_account), 0);

// reserved balance before dissolve
assert_eq!(
Balances::reserved_balance(&account_id(1)),
expected_deposit_para_registration + SubmissionDeposit::get()
);
// Dissolve returns the balance of the person who put a deposit for crowdloan
assert_ok!(Crowdloan::dissolve(signed(1), para_id));
// Crowdloan submission deposit is returned
assert_eq!(Balances::reserved_balance(&account_id(1)), expected_deposit_para_registration);

// run few blocks until lease is still active. Still a parachain.
run_to_block(early_refund_start_block + 2);
assert_eq!(Paras::lifecycle(para_id), Some(ParaLifecycle::Parachain));

// lets start a new auction from LP 8 and run it for 50 blocks so it ends before the start
// of new lease
assert_ok!(Auctions::new_auction(RuntimeOrigin::root(), 50, lease_period_index_start + 4));

// Para 1 opens a new crowdloan to renew their slot
assert_ok!(Crowdloan::create(
signed(1),
para_id,
1_000_000, // Cap
lease_period_index_start + 4, // First Slot
lease_period_index_start + 7, // Last Slot
lease_end_block, // Block End
None,
));

// Make contribution to the crowdloan
assert_ok!(Crowdloan::contribute(signed(10), para_id, 10_000, None));
let crowdloan_account =
Crowdloan::fund_account_id(Crowdloan::funds(para_id).unwrap().fund_index);

// By now, para 1 would have won another slot
run_to_block(lease_end_block);
// still a parachain
assert_eq!(Paras::lifecycle(para_id), Some(ParaLifecycle::Parachain));
// new crowdloan amount is reserved
assert_eq!(Balances::reserved_balance(&crowdloan_account), 10_000);

// new lease end block
let lease_end_block = 12 * LeasePeriod::get() + LeaseOffset::get();
run_to_block(lease_end_block);

// no more leases left, chain is downgrading
assert_eq!(Paras::lifecycle(para_id), Some(ParaLifecycle::DowngradingParachain));
assert_eq!(Balances::reserved_balance(&crowdloan_account), 0);

// 2 more sessions later it is a parathread
run_to_block(lease_end_block + 2 * BLOCKS_PER_SESSION);
assert_eq!(Paras::lifecycle(para_id), Some(ParaLifecycle::Parathread));

// Dissolve crowdloan and deregister parachain
assert_ok!(Crowdloan::withdraw(signed(10), account_id(10), para_id));
assert_ok!(Crowdloan::dissolve(signed(1), para_id));
assert_ok!(Registrar::deregister(para_origin(para_id.into()).into(), para_id));
// nothing is reserved for para manager
assert_eq!(Balances::reserved_balance(&account_id(1)), 0);
})
}
96 changes: 95 additions & 1 deletion polkadot/runtime/common/src/slots/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,102 @@

use super::*;
use crate::crowdloan;
use frame_support::traits::OnRuntimeUpgrade;
use sp_runtime::traits::AccountIdConversion;

#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;

pub mod versioned {
use super::*;

/// Wrapper over `MigrateToV1` with convenience version checks.
///
/// This migration would add a new StorageDoubleMap `LeaseInfo` and initialise it with
/// current reserved amount and a default value of 4 for lease count.
pub type ToV1<T> = frame_support::migrations::VersionedMigration<
0,
1,
v1::MigrateToV1<T>,
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;
}

mod v1 {
Ank4n marked this conversation as resolved.
Show resolved Hide resolved
use super::*;

pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);

impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
fn on_runtime_upgrade() -> Weight {
let mut weight = Weight::zero();
for (para, lease_periods) in Leases::<T>::iter() {
weight.saturating_accrue(T::DbWeight::get().reads(1));
let mut max_deposits: BTreeMap<T::AccountId, BalanceOf<T>> = BTreeMap::new();

lease_periods.iter().for_each(|lease| {
if let Some((who, amount)) = lease {
max_deposits
.entry(who.clone())
.and_modify(|deposit| *deposit = *amount.max(deposit))
.or_insert(*amount);
}
});

max_deposits.iter().for_each(|(leaser, deposit)| {
weight.saturating_accrue(T::DbWeight::get().writes(1));
// for existing leasers, set it to 4 since we don't really know how many
// past leases they had. This is generally 8 if a para applies for a full
// slot, but we initialise it to half of that.
let init_lease_period_count: LeasePeriodOf<T> = 4u32.into();
LeaseInfo::<T>::insert(para, leaser, (deposit, init_lease_period_count));
})
}

weight
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(_data: Vec<u8>) -> Result<(), TryRuntimeError> {
let mut para_leasers =
sp_std::collections::btree_set::BTreeSet::<(ParaId, T::AccountId)>::new();
for (para, lease_periods) in Leases::<T>::iter() {
lease_periods.into_iter().for_each(|maybe_lease| {
if let Some((who, _)) = maybe_lease {
para_leasers.insert((para, who));
}
});
}

// for each pair assert reserved amount is what we expect
para_leasers.iter().try_for_each(|(para, who)| -> Result<(), TryRuntimeError> {
let lease_info = LeaseInfo::<T>::get(para, who)
.expect("Migration should have inserted this entry");
let expected_deposit = Pallet::<T>::required_deposit(*para, who);
let reserved_balance = T::Currency::reserved_balance(who);

ensure!(
lease_info.0 == expected_deposit,
"reserved amount not same as required deposit"
);

ensure!(
reserved_balance >= lease_info.0,
"reserved amount value should be at least the lease reserve amount"
);

Ank4n marked this conversation as resolved.
Show resolved Hide resolved
ensure!(
lease_info.1 == 4u32.into(),
"lease count for existing leasers should be set to 4"
);

Ok(())
})
}
}
}

/// Migrations for using fund index to create fund accounts instead of para ID.
pub mod slots_crowdloan_index_migration {
use super::*;
Expand All @@ -40,7 +134,7 @@ pub mod slots_crowdloan_index_migration {
"para_id={:?}, old_fund_account={:?}, fund_id={:?}, leases={:?}",
para_id, old_fund_account, crowdloan.fund_index, leases,
);
break
break;
}
}
}
Expand Down
Loading