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

✨ Multiple migration paths #341

Merged
merged 1 commit into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
143 changes: 134 additions & 9 deletions integration-tests/src/tests/ct_migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@

use crate::*;
use frame_support::traits::{fungible::Mutate, fungibles::Inspect};
use pallet_funding::{assert_close_enough, ProjectId};
use polimec_common::migration_types::{MigrationStatus, Migrations};
use polimec_runtime::Funding;
use itertools::Itertools;
use pallet_funding::{assert_close_enough, types::*, ProjectId};
use polimec_common::migration_types::{MigrationStatus, Migrations, ParticipationType};
use polimec_runtime::{Funding, RuntimeOrigin};
use polkadot_service::chain_spec::get_account_id_from_seed;
use sp_runtime::Perquintill;
use std::collections::HashMap;
use tests::defaults::*;

fn alice() -> AccountId {
get_account_id_from_seed::<sr25519::Public>(ALICE)
}

fn mock_hrmp_establishment(project_id: u32) {
let ct_issued = PolimecNet::execute_with(|| {
<PolimecRuntime as pallet_funding::Config>::ContributionTokenCurrency::total_issuance(project_id)
Expand All @@ -34,7 +40,7 @@ fn mock_hrmp_establishment(project_id: u32) {
});

PolimecNet::execute_with(|| {
assert_ok!(Funding::do_set_para_id_for_project(&ISSUER.into(), project_id, ParaId::from(6969u32)));
assert_ok!(Funding::do_start_pallet_migration(&ISSUER.into(), project_id, ParaId::from(6969u32)));

let open_channel_message = xcm::v3::opaque::Instruction::HrmpNewChannelOpenRequest {
sender: 6969,
Expand All @@ -54,7 +60,10 @@ fn mock_hrmp_establishment(project_id: u32) {
fn assert_migration_is_ready(project_id: u32) {
PolimecNet::execute_with(|| {
let project_details = pallet_funding::ProjectsDetails::<PolimecRuntime>::get(project_id).unwrap();
assert!(project_details.migration_readiness_check.unwrap().is_ready())
let Some(MigrationType::Pallet(receiver_pallet_info)) = project_details.migration_type else {
panic!("Migration type is not ParachainReceiverPallet");
};
assert!(receiver_pallet_info.migration_readiness_check.unwrap().is_ready())
});
}

Expand All @@ -66,7 +75,7 @@ fn get_migrations_for_participants(
PolimecNet::execute_with(|| {
for participant in participants {
let (status, migrations) =
pallet_funding::UserMigrations::<PolimecRuntime>::get(project_id, participant.clone()).unwrap();
pallet_funding::UserMigrations::<PolimecRuntime>::get((project_id, participant.clone())).unwrap();
user_migrations.insert(participant, (status, Migrations::from(migrations.into())));
}
});
Expand All @@ -76,7 +85,11 @@ fn get_migrations_for_participants(
fn send_migrations(project_id: ProjectId, accounts: Vec<AccountId>) {
for user in accounts.into_iter() {
PolimecNet::execute_with(|| {
assert_ok!(Funding::migrate_one_participant(PolimecOrigin::signed(user.clone()), project_id, user.clone()));
assert_ok!(Funding::send_pallet_migration_for(
PolimecOrigin::signed(user.clone()),
project_id,
user.clone()
));
});
}
}
Expand Down Expand Up @@ -114,6 +127,10 @@ fn migrations_are_confirmed(project_id: u32, accounts: Vec<AccountId>) {
let (current_status, _) = user_migrations.get(user).unwrap();
assert_eq!(current_status, &MigrationStatus::Confirmed);
}

PolimecFunding::do_mark_project_ct_migration_as_finished(project_id).unwrap();
let project_details = pallet_funding::ProjectsDetails::<PolimecRuntime>::get(project_id).unwrap();
assert_eq!(project_details.status, pallet_funding::ProjectStatus::CTMigrationFinished)
});
}

Expand Down Expand Up @@ -174,15 +191,17 @@ fn create_settled_project() -> (ProjectId, Vec<AccountId>) {
}

#[test]
fn full_migration_test() {
fn full_pallet_migration_test() {
polimec::set_prices();
let (project_id, participants) = create_settled_project();
let project_status =
PolimecNet::execute_with(|| pallet_funding::ProjectsDetails::<PolimecRuntime>::get(project_id).unwrap().status);
dbg!(project_status);

mock_hrmp_establishment(project_id);

assert_migration_is_ready(project_id);

// Migrate is sent
send_migrations(project_id, participants.clone());

migrations_are_executed(project_id, participants.clone());
Expand All @@ -193,3 +212,109 @@ fn full_migration_test() {

migrations_are_vested(project_id, participants.clone());
}

/// Creates a project with all participations settled except for one.
fn create_project_with_unsettled_participation(participation_type: ParticipationType) -> (ProjectId, Vec<AccountId>) {
let mut inst = IntegrationInstantiator::new(None);
PolimecNet::execute_with(|| {
let project_id = inst.create_finished_project(
default_project_metadata(ISSUER.into()),
ISSUER.into(),
default_evaluations(),
default_bids(),
default_community_contributions(),
default_remainder_contributions(),
);

inst.advance_time(<PolimecRuntime as pallet_funding::Config>::SuccessToSettlementTime::get()).unwrap();
let evaluations_to_settle =
pallet_funding::Evaluations::<PolimecRuntime>::iter_prefix_values((project_id,)).collect_vec();
let bids_to_settle = pallet_funding::Bids::<PolimecRuntime>::iter_prefix_values((project_id,)).collect_vec();
let contributions_to_settle =
pallet_funding::Contributions::<PolimecRuntime>::iter_prefix_values((project_id,)).collect_vec();

let mut participants: Vec<AccountId> = evaluations_to_settle
.iter()
.map(|eval| eval.evaluator.clone())
.chain(bids_to_settle.iter().map(|bid| bid.bidder.clone()))
.chain(contributions_to_settle.iter().map(|contribution| contribution.contributor.clone()))
.collect();
participants.sort();
participants.dedup();

let start = if participation_type == ParticipationType::Evaluation { 1 } else { 0 };
for evaluation in evaluations_to_settle[start..].iter() {
PolimecFunding::settle_successful_evaluation(
RuntimeOrigin::signed(alice()),
project_id,
evaluation.evaluator.clone(),
evaluation.id,
)
.unwrap()
}

let start = if participation_type == ParticipationType::Bid { 1 } else { 0 };
for bid in bids_to_settle[start..].iter() {
PolimecFunding::settle_successful_bid(
RuntimeOrigin::signed(alice()),
project_id,
bid.bidder.clone(),
bid.id,
)
.unwrap()
}

let start = if participation_type == ParticipationType::Contribution { 1 } else { 0 };
for contribution in contributions_to_settle[start..].iter() {
PolimecFunding::settle_successful_contribution(
RuntimeOrigin::signed(alice()),
project_id,
contribution.contributor.clone(),
contribution.id,
)
.unwrap()
}

let evaluations =
pallet_funding::Evaluations::<PolimecRuntime>::iter_prefix_values((project_id,)).collect_vec();
let bids = pallet_funding::Bids::<PolimecRuntime>::iter_prefix_values((project_id,)).collect_vec();
let contributions =
pallet_funding::Contributions::<PolimecRuntime>::iter_prefix_values((project_id,)).collect_vec();

if participation_type == ParticipationType::Evaluation {
assert_eq!(evaluations.len(), 1);
assert_eq!(bids.len(), 0);
assert_eq!(contributions.len(), 0);
} else if participation_type == ParticipationType::Bid {
assert_eq!(evaluations.len(), 0);
assert_eq!(bids.len(), 1);
assert_eq!(contributions.len(), 0);
} else {
assert_eq!(evaluations.len(), 0);
assert_eq!(bids.len(), 0);
assert_eq!(contributions.len(), 1);
}

(project_id, participants)
})
}

#[test]
fn cannot_start_pallet_migration_with_unsettled_participations() {
polimec::set_prices();

let tup_1 = create_project_with_unsettled_participation(ParticipationType::Evaluation);
let tup_2 = create_project_with_unsettled_participation(ParticipationType::Bid);
let tup_3 = create_project_with_unsettled_participation(ParticipationType::Contribution);

let tups = vec![tup_1, tup_2, tup_3];

for (project_id, participants) in tups.into_iter() {
PolimecNet::execute_with(|| {
assert_noop!(
PolimecFunding::do_start_pallet_migration(&ISSUER.into(), project_id, ParaId::from(6969u32)),
pallet_funding::Error::<PolimecRuntime>::SettlementNotComplete
);
});
}
}
9 changes: 6 additions & 3 deletions integration-tests/src/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ fn ct_migrated() {
// Mock HRMP establishment
PolimecNet::execute_with(|| {
let _account_id: PolimecAccountId = ISSUER.into();
assert_ok!(PolimecFunding::do_set_para_id_for_project(&ISSUER.into(), project_id, ParaId::from(6969u32),));
assert_ok!(PolimecFunding::do_start_pallet_migration(&ISSUER.into(), project_id, ParaId::from(6969u32),));
let open_channel_message = xcm::v3::opaque::Instruction::HrmpNewChannelOpenRequest {
sender: 6969,
max_message_size: 102_300,
Expand All @@ -505,7 +505,10 @@ fn ct_migrated() {
// Migration is ready
PolimecNet::execute_with(|| {
let project_details = pallet_funding::ProjectsDetails::<PolimecRuntime>::get(project_id).unwrap();
assert!(project_details.migration_readiness_check.unwrap().is_ready())
let Some(MigrationType::Pallet(migration_info)) = project_details.migration_type else {
panic!("Migration type should be ParachainReceiverPallet");
};
assert!(migration_info.migration_readiness_check.unwrap().is_ready())
});

excel_ct_amounts().iter().map(|tup| tup.0.clone()).unique().for_each(|account| {
Expand All @@ -525,7 +528,7 @@ fn ct_migrated() {

for account in accounts {
PolimecNet::execute_with(|| {
assert_ok!(PolimecFunding::migrate_one_participant(
assert_ok!(PolimecFunding::send_pallet_migration_for(
PolimecOrigin::signed(account.clone()),
project_id,
account.clone()
Expand Down
29 changes: 22 additions & 7 deletions pallets/funding/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,7 +1535,10 @@ mod benchmarks {
inst.create_finished_project(project_metadata, issuer, evaluations, bids, contributions, vec![]);

inst.advance_time(One::one()).unwrap();
assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed);
assert_eq!(
inst.get_project_details(project_id).status,
ProjectStatus::SettlementStarted(FundingOutcome::FundingFailed)
);

let evaluation_to_settle =
inst.execute(|| Evaluations::<T>::iter_prefix_values((project_id, evaluator.clone())).next().unwrap());
Expand Down Expand Up @@ -1606,7 +1609,10 @@ mod benchmarks {

run_blocks_to_execute_next_transition(project_id, UpdateType::StartSettlement, &mut inst);

assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingSuccessful);
assert_eq!(
inst.get_project_details(project_id).status,
ProjectStatus::SettlementStarted(FundingOutcome::FundingSuccessful)
);

let bid_to_settle =
inst.execute(|| Bids::<T>::iter_prefix_values((project_id, bidder.clone())).next().unwrap());
Expand Down Expand Up @@ -1665,7 +1671,10 @@ mod benchmarks {
inst.create_finished_project(project_metadata, issuer.clone(), evaluations, bids, contributions, vec![]);

inst.advance_time(One::one()).unwrap();
assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed);
assert_eq!(
inst.get_project_details(project_id).status,
ProjectStatus::SettlementStarted(FundingOutcome::FundingFailed)
);

let bid_to_settle =
inst.execute(|| Bids::<T>::iter_prefix_values((project_id, bidder.clone())).next().unwrap());
Expand Down Expand Up @@ -1713,7 +1722,10 @@ mod benchmarks {

run_blocks_to_execute_next_transition(project_id, UpdateType::StartSettlement, &mut inst);

assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingSuccessful);
assert_eq!(
inst.get_project_details(project_id).status,
ProjectStatus::SettlementStarted(FundingOutcome::FundingSuccessful)
);

let contribution_to_settle =
inst.execute(|| Contributions::<T>::iter_prefix_values((project_id, contributor.clone())).next().unwrap());
Expand Down Expand Up @@ -1783,7 +1795,10 @@ mod benchmarks {
inst.create_finished_project(project_metadata, issuer, evaluations, bids, contributions, vec![]);

inst.advance_time(One::one()).unwrap();
assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed);
assert_eq!(
inst.get_project_details(project_id).status,
ProjectStatus::SettlementStarted(FundingOutcome::FundingFailed)
);

let contribution_to_settle =
inst.execute(|| Contributions::<T>::iter_prefix_values((project_id, contributor.clone())).next().unwrap());
Expand Down Expand Up @@ -2618,7 +2633,7 @@ mod benchmarks {

// * validity checks *
let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::FundingSuccessful);
assert_eq!(project_details.status, ProjectStatus::SettlementStarted(FundingOutcome::FundingSuccessful));
}

#[benchmark]
Expand Down Expand Up @@ -2667,7 +2682,7 @@ mod benchmarks {

// * validity checks *
let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::FundingFailed);
assert_eq!(project_details.status, ProjectStatus::SettlementStarted(FundingOutcome::FundingFailed));
}

#[cfg(test)]
Expand Down
7 changes: 1 addition & 6 deletions pallets/funding/src/functions/1_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,7 @@ impl<T: Config> Pallet<T> {
},
usd_bid_on_oversubscription: None,
funding_end_block: None,
parachain_id: None,
migration_readiness_check: None,
hrmp_channel_status: HRMPChannelStatus {
project_to_polimec: ChannelStatus::Closed,
polimec_to_project: ChannelStatus::Closed,
},
migration_type: None,
};

let bucket: BucketOf<T> = Self::create_bucket_from_metadata(&project_metadata)?;
Expand Down
Loading