diff --git a/justfile b/justfile index 5fbeadc37..20668115b 100644 --- a/justfile +++ b/justfile @@ -72,6 +72,23 @@ benchmark-pallet chain="polimec-paseo-local" pallet="pallet-dispenser": --output=pallets/{{ replace(pallet, "pallet-", "") }}/src/weights.rs \ --template=./.maintain/frame-weight-template.hbs + +benchmark-extrinsics pallet="pallet-funding" extrinsics="*" : + cargo run --features runtime-benchmarks --profile=production -p polimec-node benchmark pallet \ + --chain=polimec-paseo-local \ + --steps=10 \ + --repeat=5 \ + --pallet={{ pallet }} \ + --no-storage-info \ + --no-median-slopes \ + --no-min-squares \ + --extrinsic={{ extrinsics }} \ + --wasm-execution=compiled \ + --heap-pages=4096 \ + --output=benchmarked-extrinsics.rs \ + --template=./.maintain/frame-weight-template.hbs + + # Build the Node Docker Image docker-build tag="latest" package="polimec-node": ./scripts/build_image.sh {{ tag }} ./Dockerfile {{ package }} diff --git a/nodes/parachain/src/chain_spec/common.rs b/nodes/parachain/src/chain_spec/common.rs index 0b02e8e50..9295da6a5 100644 --- a/nodes/parachain/src/chain_spec/common.rs +++ b/nodes/parachain/src/chain_spec/common.rs @@ -87,10 +87,6 @@ pub fn genesis_config(genesis_config_params: GenesisConfigParams) -> serde_json: } = genesis_config_params; let system_accounts = vec![ - ( - ::BlockchainOperationTreasury::get(), - ::NativeCurrency::minimum_balance(), - ), ( ::ContributionTreasury::get(), ::NativeCurrency::minimum_balance(), diff --git a/nodes/parachain/src/chain_spec/polimec_paseo.rs b/nodes/parachain/src/chain_spec/polimec_paseo.rs index 053fc5c05..7387bf20b 100644 --- a/nodes/parachain/src/chain_spec/polimec_paseo.rs +++ b/nodes/parachain/src/chain_spec/polimec_paseo.rs @@ -25,7 +25,8 @@ use polimec_runtime::{AccountId, MinCandidateStk}; pub fn get_local_chain_spec() -> GenericChainSpec { let endowed_accounts = vec![alice(), bob(), charlie(), dave()]; - let endowed_accounts = endowed_accounts.iter().map(|x| (x.clone(), MinCandidateStk::get() * 5)).collect::>(); + let endowed_accounts = + endowed_accounts.iter().map(|x| (x.clone(), MinCandidateStk::get() * 20)).collect::>(); let genesis_config_params = GenesisConfigParams { stakers: vec![alice(), bob()], council_members: vec![alice()], diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs index 6a6e3cab5..7d9929bd9 100644 --- a/pallets/funding/src/benchmarking.rs +++ b/pallets/funding/src/benchmarking.rs @@ -19,23 +19,32 @@ //! Benchmarking setup for Funding pallet use super::*; -use crate::{instantiator::*, traits::ProvideAssetPrice}; +use crate::{ + instantiator::*, + traits::{ProvideAssetPrice, SetPrices}, +}; use frame_benchmarking::v2::*; #[cfg(test)] use frame_support::assert_ok; use frame_support::{ dispatch::RawOrigin, - traits::{fungibles::metadata::MetadataDeposit, OriginTrait}, + traits::{ + fungibles::{metadata::MetadataDeposit, Inspect}, + OriginTrait, + }, Parameter, }; +use itertools::Itertools; #[allow(unused_imports)] use pallet::Pallet as PalletFunding; use parity_scale_codec::{Decode, Encode}; use polimec_common::{credentials::InvestorType, USD_DECIMALS, USD_UNIT}; +use polimec_common_test_utils::{generate_did_from_account, get_mock_jwt_with_cid}; use sp_arithmetic::Percent; use sp_core::H256; use sp_io::hashing::blake2_256; use sp_runtime::traits::{Get, Member, TrailingZeroInput, Zero}; +use xcm::v3::MaxPalletNameLen; const IPFS_CID: &str = "QmbvsJBhQtu9uAGVp7x4H77JkwAQxV7TA6xTfdeALuDiYB"; const CT_DECIMALS: u8 = 17; @@ -308,16 +317,13 @@ pub fn run_blocks_to_execute_next_transition( T: Config + frame_system::Config::RuntimeEvent> + pallet_balances::Config>, ::RuntimeEvent: TryInto> + Parameter + Member, ::Price: From, - ::Balance: From, + ::Balance: From + Into, T::Hash: From, ::AccountId: Into<<::RuntimeOrigin as OriginTrait>::AccountId> + sp_std::fmt::Debug, ::Balance: Into>, )] mod benchmarks { use super::*; - use crate::traits::SetPrices; - use itertools::Itertools; - use polimec_common_test_utils::{generate_did_from_account, get_mock_jwt_with_cid}; impl_benchmark_test_suite!(PalletFunding, crate::mock::new_test_ext(), crate::mock::TestRuntime); @@ -1544,8 +1550,7 @@ mod benchmarks { inst.execute(|| Evaluations::::iter_prefix_values((project_id, evaluator.clone())).next().unwrap()); let treasury_account = T::BlockchainOperationTreasury::get(); - let free_treasury_plmc = inst.get_free_plmc_balances_for(vec![treasury_account])[0].plmc_amount; - assert_eq!(free_treasury_plmc, inst.get_ed()); + let prev_free_treasury_plmc = inst.get_free_plmc_balances_for(vec![treasury_account])[0].plmc_amount; #[extrinsic_call] settle_failed_evaluation( @@ -1567,9 +1572,8 @@ mod benchmarks { assert_eq!(reserved_plmc, 0.into()); let treasury_account = T::BlockchainOperationTreasury::get(); - let free_treasury_plmc = inst.get_free_plmc_balances_for(vec![treasury_account])[0].plmc_amount; - let ed = inst.get_ed(); - assert_eq!(free_treasury_plmc, slashed_amount + ed); + let post_free_treasury_plmc = inst.get_free_plmc_balances_for(vec![treasury_account])[0].plmc_amount; + assert_eq!(post_free_treasury_plmc, prev_free_treasury_plmc + slashed_amount); // Events frame_system::Pallet::::assert_last_event( @@ -2623,9 +2627,6 @@ mod benchmarks { vec![], ); - // let issuer_mint = UserToPLMCBalance::::new(issuer.clone(), (100 * ASSET_UNIT).into()); - // inst.mint_plmc_to(vec![issuer_mint]); - #[block] { Pallet::::do_start_settlement(project_id).unwrap(); @@ -2685,6 +2686,660 @@ mod benchmarks { assert_eq!(project_details.status, ProjectStatus::SettlementStarted(FundingOutcome::FundingFailed)); } + #[benchmark] + fn start_pallet_migration() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + #[extrinsic_call] + start_pallet_migration(RawOrigin::Signed(issuer), jwt, project_id, ParaId::from(6969)); + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted); + assert_eq!( + project_details.migration_type, + Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Closed, + polimec_to_project: ChannelStatus::Closed + }, + migration_readiness_check: None, + })) + ) + } + + #[benchmark] + fn start_offchain_migration() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + #[extrinsic_call] + start_offchain_migration(RawOrigin::Signed(issuer), jwt, project_id); + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted); + assert_eq!(UnmigratedCounter::::get(project_id), 13); + } + + #[benchmark] + fn confirm_offchain_migration( + // Amount of migrations to confirm for a single user + x: Linear<1, { MaxParticipationsPerUser::::get() }>, + ) { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + let participant = account::>("test_participant", 0, 0); + + let max_evaluations = (x / 3).min(::MaxEvaluationsPerUser::get()); + let max_bids = ((x - max_evaluations) / 2).min(::MaxBidsPerUser::get()); + let max_contributions = x - max_evaluations - max_bids; + + let participant_evaluations = (0..max_evaluations) + .map(|_| UserToUSDBalance::new(participant.clone(), (100 * USD_UNIT).into())) + .collect_vec(); + let participant_bids = (0..max_bids) + .map(|_| BidParams::new(participant.clone(), (500 * CT_UNIT).into(), 1u8, AcceptedFundingAsset::USDT)) + .collect_vec(); + let participant_contributions = (0..max_contributions) + .map(|_| { + ContributionParams::::new( + participant.clone(), + (10 * CT_UNIT).into(), + 1u8, + AcceptedFundingAsset::USDT, + ) + }) + .collect_vec(); + + let mut evaluations = default_evaluations::(); + evaluations.extend(participant_evaluations); + + let mut bids = default_bids::(); + bids.extend(participant_bids); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + evaluations, + bids, + default_community_contributions::(), + participant_contributions, + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_offchain_migration(RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id) + .unwrap(); + + let participant_migrations_len = UserMigrations::::get((project_id, participant.clone())).unwrap().1.len(); + assert_eq!(participant_migrations_len as u32, x); + + #[extrinsic_call] + confirm_offchain_migration(RawOrigin::Signed(issuer), project_id, participant); + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted); + assert_eq!(UnmigratedCounter::::get(project_id), 13); + } + + #[benchmark] + fn mark_project_ct_migration_as_finished() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_offchain_migration(RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id) + .unwrap(); + + let participants = UserMigrations::::iter_key_prefix((project_id,)).collect_vec(); + for participant in participants { + >::confirm_offchain_migration( + RawOrigin::Signed(issuer.clone().clone()).into(), + project_id, + participant, + ) + .unwrap() + } + + #[extrinsic_call] + mark_project_ct_migration_as_finished(RawOrigin::Signed(issuer), project_id); + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::CTMigrationFinished); + assert_eq!(UnmigratedCounter::::get(project_id), 0); + assert_eq!( + UserMigrations::::iter_prefix_values((project_id,)) + .map(|item| item.0) + .all(|status| status == MigrationStatus::Confirmed), + true + ); + } + + #[benchmark] + fn start_pallet_migration_readiness_check() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_pallet_migration( + RawOrigin::Signed(issuer.clone()).into(), + jwt.clone(), + project_id, + 6969u32.into(), + ) + .unwrap(); + + // Mock hrmp establishment + let mut project_details = inst.get_project_details(project_id); + project_details.migration_type = Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Open, + polimec_to_project: ChannelStatus::Open, + }, + migration_readiness_check: Some(PalletMigrationReadinessCheck { + holding_check: (0, CheckOutcome::Failed), + pallet_check: (1, CheckOutcome::Failed), + }), + })); + ProjectsDetails::::insert(project_id, project_details); + + #[extrinsic_call] + start_pallet_migration_readiness_check(RawOrigin::Signed(issuer.clone()), jwt, project_id); + + // * validity checks * + frame_system::Pallet::::assert_last_event( + Event::::MigrationReadinessCheckStarted { project_id, caller: issuer.clone() }.into(), + ); + } + + #[benchmark] + fn pallet_migration_readiness_response_holding() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_pallet_migration( + RawOrigin::Signed(issuer.clone()).into(), + jwt.clone(), + project_id, + 6969u32.into(), + ) + .unwrap(); + + // Mock hrmp establishment + let mut project_details = inst.get_project_details(project_id); + project_details.migration_type = Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Open, + polimec_to_project: ChannelStatus::Open, + }, + migration_readiness_check: None, + })); + ProjectsDetails::::insert(project_id, project_details); + + // Create query id's + crate::Pallet::::do_start_pallet_migration_readiness_check( + &T::PalletId::get().into_account_truncating(), + project_id, + ) + .unwrap(); + + let ct_issuance: u128 = ::ContributionTokenCurrency::total_issuance(project_id).into(); + let xcm_response = Response::Assets( + vec![MultiAsset { id: Concrete(MultiLocation::new(1, X1(Parachain(6969)))), fun: Fungible(ct_issuance) }] + .into(), + ); + + #[block] + { + // We call the inner function directly to avoid having to hardcode a benchmark pallet_xcm origin as a config type + crate::Pallet::::do_pallet_migration_readiness_response( + MultiLocation::new(1, X1(Parachain(6969))), + 0, + xcm_response.clone(), + ) + .unwrap(); + } + + // * validity checks * + frame_system::Pallet::::assert_last_event( + Event::::MigrationCheckResponseAccepted { project_id, query_id: 0, response: xcm_response }.into(), + ); + } + + #[benchmark] + fn pallet_migration_readiness_response_pallet_info() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_pallet_migration( + RawOrigin::Signed(issuer.clone()).into(), + jwt.clone(), + project_id, + 6969u32.into(), + ) + .unwrap(); + + // Mock hrmp establishment + let mut project_details = inst.get_project_details(project_id); + project_details.migration_type = Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Open, + polimec_to_project: ChannelStatus::Open, + }, + migration_readiness_check: None, + })); + ProjectsDetails::::insert(project_id, project_details); + + // Create query id's + crate::Pallet::::do_start_pallet_migration_readiness_check( + &T::PalletId::get().into_account_truncating(), + project_id, + ) + .unwrap(); + + let module_name: BoundedVec = + BoundedVec::try_from("polimec_receiver".as_bytes().to_vec()).unwrap(); + let pallet_info = xcm::latest::PalletInfo { + // index is used for future `Transact` calls to the pallet for migrating a user + index: 69, + // Doesn't matter + name: module_name.clone(), + // Main check that the receiver pallet is there + module_name, + // These might be useful in the future, but not for now + major: 0, + minor: 0, + patch: 0, + }; + let xcm_response = Response::PalletsInfo(vec![pallet_info].try_into().unwrap()); + + #[block] + { + // We call the inner function directly to avoid having to hardcode a benchmark pallet_xcm origin as a config type + crate::Pallet::::do_pallet_migration_readiness_response( + MultiLocation::new(1, X1(Parachain(6969))), + 1, + xcm_response.clone(), + ) + .unwrap(); + } + + // * validity checks * + frame_system::Pallet::::assert_last_event( + Event::::MigrationCheckResponseAccepted { project_id, query_id: 1, response: xcm_response }.into(), + ); + } + + #[benchmark] + fn send_pallet_migration_for( + // Amount of migrations to confirm for a single user + x: Linear<1, { MaxParticipationsPerUser::::get() }>, + ) { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + let participant = account::>("test_participant", 0, 0); + + let max_evaluations = (x / 3).min(::MaxEvaluationsPerUser::get()); + let max_bids = ((x - max_evaluations) / 2).min(::MaxBidsPerUser::get()); + let max_contributions = x - max_evaluations - max_bids; + + let participant_evaluations = (0..max_evaluations) + .map(|_| UserToUSDBalance::new(participant.clone(), (100 * USD_UNIT).into())) + .collect_vec(); + let participant_bids = (0..max_bids) + .map(|_| BidParams::new(participant.clone(), (500 * CT_UNIT).into(), 1u8, AcceptedFundingAsset::USDT)) + .collect_vec(); + let participant_contributions = (0..max_contributions) + .map(|_| { + ContributionParams::::new( + participant.clone(), + (10 * CT_UNIT).into(), + 1u8, + AcceptedFundingAsset::USDT, + ) + }) + .collect_vec(); + + let mut evaluations = default_evaluations::(); + evaluations.extend(participant_evaluations); + + let mut bids = default_bids::(); + bids.extend(participant_bids); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + evaluations, + bids, + default_community_contributions::(), + participant_contributions, + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_pallet_migration( + RawOrigin::Signed(issuer.clone()).into(), + jwt.clone(), + project_id, + 6969u32.into(), + ) + .unwrap(); + + // Mock hrmp establishment + let mut project_details = inst.get_project_details(project_id); + project_details.migration_type = Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Open, + polimec_to_project: ChannelStatus::Open, + }, + migration_readiness_check: Some(PalletMigrationReadinessCheck { + holding_check: (0, CheckOutcome::Passed(None)), + pallet_check: (1, CheckOutcome::Passed(Some(42))), + }), + })); + ProjectsDetails::::insert(project_id, project_details); + + #[extrinsic_call] + send_pallet_migration_for(RawOrigin::Signed(issuer), project_id, participant.clone()); + + // * validity checks * + frame_system::Pallet::::assert_last_event( + Event::::MigrationStatusUpdated { project_id, account: participant, status: MigrationStatus::Sent(0) } + .into(), + ); + } + + #[benchmark] + fn confirm_pallet_migrations( + // Amount of migrations to confirm for a single user + x: Linear<1, { MaxParticipationsPerUser::::get() }>, + ) { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + let participant = account::>("test_participant", 0, 0); + + let max_evaluations = (x / 3).min(::MaxEvaluationsPerUser::get()); + let max_bids = ((x - max_evaluations) / 2).min(::MaxBidsPerUser::get()); + let max_contributions = x - max_evaluations - max_bids; + + let participant_evaluations = (0..max_evaluations) + .map(|_| UserToUSDBalance::new(participant.clone(), (100 * USD_UNIT).into())) + .collect_vec(); + let participant_bids = (0..max_bids) + .map(|_| BidParams::new(participant.clone(), (500 * CT_UNIT).into(), 1u8, AcceptedFundingAsset::USDT)) + .collect_vec(); + let participant_contributions = (0..max_contributions) + .map(|_| { + ContributionParams::::new( + participant.clone(), + (10 * CT_UNIT).into(), + 1u8, + AcceptedFundingAsset::USDT, + ) + }) + .collect_vec(); + + let mut evaluations = default_evaluations::(); + evaluations.extend(participant_evaluations); + + let mut bids = default_bids::(); + bids.extend(participant_bids); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_finished_project( + project_metadata.clone(), + issuer.clone(), + evaluations, + bids, + default_community_contributions::(), + participant_contributions, + ); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + inst.settle_project(project_id).unwrap(); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_pallet_migration( + RawOrigin::Signed(issuer.clone()).into(), + jwt.clone(), + project_id, + 6969u32.into(), + ) + .unwrap(); + + // Mock hrmp establishment + let mut project_details = inst.get_project_details(project_id); + project_details.migration_type = Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Open, + polimec_to_project: ChannelStatus::Open, + }, + migration_readiness_check: Some(PalletMigrationReadinessCheck { + holding_check: (0, CheckOutcome::Passed(None)), + pallet_check: (1, CheckOutcome::Passed(Some(42))), + }), + })); + ProjectsDetails::::insert(project_id, project_details); + + crate::Pallet::::send_pallet_migration_for( + RawOrigin::Signed(issuer).into(), + project_id, + participant.clone(), + ) + .unwrap(); + + let project_location = MultiLocation::new(1, X1(Parachain(6969))); + let xcm_response = Response::DispatchResult(MaybeErrorCode::Success); + + #[block] + { + crate::Pallet::::do_confirm_pallet_migrations(project_location, 0, xcm_response).unwrap(); + } + + // * validity checks * + frame_system::Pallet::::assert_last_event( + Event::::MigrationStatusUpdated { project_id, account: participant, status: MigrationStatus::Confirmed } + .into(), + ); + } + #[cfg(test)] mod tests { use super::*; @@ -2886,5 +3541,68 @@ mod benchmarks { assert_ok!(PalletFunding::::test_end_funding_awaiting_decision_evaluators_slashed()); }); } + + #[test] + fn bench_start_pallet_migration() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_start_pallet_migration()); + }); + } + + #[test] + fn bench_start_offchain_migration() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_start_offchain_migration()); + }); + } + + #[test] + fn bench_confirm_offchain_migration() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_confirm_offchain_migration()); + }); + } + + #[test] + fn bench_mark_project_ct_migration_as_finished() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_mark_project_ct_migration_as_finished()); + }); + } + + #[test] + fn bench_start_pallet_migration_readiness_check() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_start_pallet_migration_readiness_check()); + }); + } + + #[test] + fn bench_pallet_migration_readiness_response_holding() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_pallet_migration_readiness_response_holding()); + }); + } + + #[test] + fn bench_pallet_migration_readiness_response_pallet_info() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_pallet_migration_readiness_response_pallet_info()); + }); + } + + #[test] + fn bench_send_pallet_migration_for() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_send_pallet_migration_for()); + }); + } + + #[test] + fn bench_confirm_pallet_migrations() { + new_test_ext().execute_with(|| { + assert_ok!(PalletFunding::::test_confirm_pallet_migrations()); + }); + } } } diff --git a/pallets/funding/src/functions/7_ct_migration.rs b/pallets/funding/src/functions/7_ct_migration.rs index ed58f90f1..c19b8bfa7 100644 --- a/pallets/funding/src/functions/7_ct_migration.rs +++ b/pallets/funding/src/functions/7_ct_migration.rs @@ -266,7 +266,10 @@ impl Pallet { } // * Update storage * - let call = Call::::pallet_migration_readiness_response { query_id: Default::default(), response: Default::default() }; + let call = Call::::pallet_migration_readiness_response { + query_id: Default::default(), + response: Default::default(), + }; let query_id_holdings = pallet_xcm::Pallet::::new_notify_query( project_multilocation.clone(), diff --git a/pallets/funding/src/instantiator/chain_interactions.rs b/pallets/funding/src/instantiator/chain_interactions.rs index 377ca31ab..7a9df9ada 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -1041,7 +1041,6 @@ impl< }, _ => {}, }; - let ct_price = self.get_project_details(project_id).weighted_average_price.unwrap(); let contributors = remainder_contributions.accounts(); let asset_id = remainder_contributions[0].asset.to_assethub_id(); @@ -1055,8 +1054,14 @@ impl< let plmc_remainder_contribution_deposits = self.calculate_contributed_plmc_spent(remainder_contributions.clone(), ct_price, false); + let reducible_evaluator_balances = self.slash_evaluator_balances(plmc_evaluation_deposits); + let remaining_reducible_evaluator_balances = self.generic_map_operation( + vec![reducible_evaluator_balances, plmc_bid_deposits.clone()], + MergeOperation::Subtract, + ); + let necessary_plmc_mint = self.generic_map_operation( - vec![plmc_remainder_contribution_deposits.clone(), plmc_evaluation_deposits], + vec![plmc_remainder_contribution_deposits.clone(), remaining_reducible_evaluator_balances], MergeOperation::Subtract, ); let total_plmc_participation_locked = self.generic_map_operation( @@ -1087,10 +1092,7 @@ impl< total_plmc_participation_locked.merge_accounts(MergeOperation::Add), HoldReason::Participation(project_id).into(), ); - self.do_contribution_transferred_foreign_asset_assertions( - funding_asset_deposits.merge_accounts(MergeOperation::Add), - project_id, - ); + self.do_contribution_transferred_foreign_asset_assertions(funding_asset_deposits, project_id); self.do_free_plmc_assertions(expected_free_plmc_balances.merge_accounts(MergeOperation::Add)); self.do_free_foreign_asset_assertions(prev_funding_asset_balances.merge_accounts(MergeOperation::Add)); assert_eq!(self.get_plmc_total_supply(), post_supply); diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index 3f149bbbe..61737c099 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -1011,7 +1011,6 @@ pub mod pallet { Self::do_start_community_funding(project_id) } - /// Buy tokens in the Community or Remainder round at the price set in the Auction Round #[pallet::call_index(12)] #[pallet::weight( @@ -1226,9 +1225,8 @@ pub mod pallet { Self::do_settle_failed_contribution(bid, project_id) } - // TODO: add weight #[pallet::call_index(25)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::start_pallet_migration())] pub fn start_pallet_migration( origin: OriginFor, jwt: UntrustedToken, @@ -1242,9 +1240,8 @@ pub mod pallet { Self::do_start_pallet_migration(&account, project_id, para_id) } - // TODO: add weight #[pallet::call_index(26)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::start_offchain_migration())] pub fn start_offchain_migration( origin: OriginFor, jwt: UntrustedToken, @@ -1257,9 +1254,8 @@ pub mod pallet { Self::do_start_offchain_migration(project_id, account) } - // TODO: add weight #[pallet::call_index(27)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::start_pallet_migration_readiness_check())] pub fn start_pallet_migration_readiness_check( origin: OriginFor, jwt: UntrustedToken, @@ -1272,9 +1268,9 @@ pub mod pallet { } /// Called only by other chains through a query response xcm message - // TODO: add weight #[pallet::call_index(28)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::pallet_migration_readiness_response_pallet_info() + .max(WeightInfoOf::::pallet_migration_readiness_response_holding()))] pub fn pallet_migration_readiness_response( origin: OriginFor, query_id: xcm::v3::QueryId, @@ -1285,9 +1281,8 @@ pub mod pallet { Self::do_pallet_migration_readiness_response(location, query_id, response) } - // TODO: add weight #[pallet::call_index(29)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::send_pallet_migration_for(MaxParticipationsPerUser::::get()))] pub fn send_pallet_migration_for( origin: OriginFor, project_id: ProjectId, @@ -1297,9 +1292,8 @@ pub mod pallet { Self::do_send_pallet_migration_for(project_id, participant) } - // TODO: add weight #[pallet::call_index(30)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::confirm_pallet_migrations(MaxParticipationsPerUser::::get()))] pub fn confirm_pallet_migrations( origin: OriginFor, query_id: QueryId, @@ -1310,9 +1304,8 @@ pub mod pallet { Self::do_confirm_pallet_migrations(location, query_id, response) } - // TODO: add weight #[pallet::call_index(31)] - #[pallet::weight(Weight::from_parts(1000, 0))] + #[pallet::weight(WeightInfoOf::::confirm_offchain_migration(MaxParticipationsPerUser::::get()))] pub fn confirm_offchain_migration( origin: OriginFor, project_id: ProjectId, @@ -1323,13 +1316,9 @@ pub mod pallet { Self::do_confirm_offchain_migration(project_id, caller, participant) } - // TODO: add weight #[pallet::call_index(32)] - #[pallet::weight(Weight::from_parts(1000, 0))] - pub fn mark_project_migration_as_finished( - origin: OriginFor, - project_id: ProjectId, - ) -> DispatchResult { + #[pallet::weight(WeightInfoOf::::mark_project_ct_migration_as_finished())] + pub fn mark_project_ct_migration_as_finished(origin: OriginFor, project_id: ProjectId) -> DispatchResult { let _caller = ensure_signed(origin)?; Self::do_mark_project_ct_migration_as_finished(project_id) diff --git a/pallets/funding/src/mock.rs b/pallets/funding/src/mock.rs index 92005f843..df417a539 100644 --- a/pallets/funding/src/mock.rs +++ b/pallets/funding/src/mock.rs @@ -30,7 +30,7 @@ use frame_support::{ }; use frame_system as system; use frame_system::{EnsureRoot, RawOrigin as SystemRawOrigin}; -use polimec_common::{credentials::EnsureInvestor, USD_UNIT}; +use polimec_common::{credentials::EnsureInvestor, DummyXcmSender, USD_UNIT}; use polkadot_parachain_primitives::primitives::Sibling; use sp_arithmetic::Percent; use sp_core::H256; @@ -138,19 +138,6 @@ impl ExecuteXcm for MockXcmExecutor { Ok(()) } } -pub struct DummyXcmSender; -impl SendXcm for DummyXcmSender { - type Ticket = (); - - fn validate(_: &mut Option, _: &mut Option>) -> SendResult { - Ok(((), MultiAssets::new())) - } - - /// Actually carry out the delivery operation for a previously validated message sending. - fn deliver(_ticket: Self::Ticket) -> Result { - Ok([0u8; 32]) - } -} impl pallet_xcm::Config for TestRuntime { type AdminOrigin = EnsureRoot; diff --git a/pallets/funding/src/tests/5_remainder.rs b/pallets/funding/src/tests/5_remainder.rs index 6cda38c95..62880486b 100644 --- a/pallets/funding/src/tests/5_remainder.rs +++ b/pallets/funding/src/tests/5_remainder.rs @@ -1165,6 +1165,35 @@ mod remaining_contribute_extrinsic { }; assert_eq!(account_data, expected_account_data); } + + #[test] + fn participant_was_evaluator_and_bidder() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let issuer = ISSUER_1; + let participant = 42069u32; + let project_metadata = default_project_metadata(issuer); + let mut evaluations = default_evaluations(); + evaluations.push((participant, 100 * USD_UNIT).into()); + let mut bids = default_bids(); + bids.push(BidParams::new(participant, 1000 * CT_UNIT, 1u8, AcceptedFundingAsset::USDT)); + let community_contributions = default_community_buys(); + let mut remainder_contributions = default_remainder_buys(); + remainder_contributions.push(ContributionParams::new( + participant, + 10 * CT_UNIT, + 1u8, + AcceptedFundingAsset::USDT, + )); + + let _project_id = inst.create_finished_project( + project_metadata.clone(), + issuer, + evaluations, + bids, + community_contributions, + remainder_contributions, + ); + } } #[cfg(test)] diff --git a/pallets/funding/src/weights.rs b/pallets/funding/src/weights.rs index 7a9f177c7..dd2f06784 100644 --- a/pallets/funding/src/weights.rs +++ b/pallets/funding/src/weights.rs @@ -82,6 +82,15 @@ pub trait WeightInfo { fn project_decision() -> Weight; fn start_settlement_funding_success() -> Weight; fn start_settlement_funding_failure() -> Weight; + fn start_pallet_migration() -> Weight; + fn start_offchain_migration() -> Weight; + fn confirm_offchain_migration(_x: u32) -> Weight; + fn mark_project_ct_migration_as_finished() -> Weight; + fn start_pallet_migration_readiness_check() -> Weight; + fn pallet_migration_readiness_response_holding() -> Weight; + fn pallet_migration_readiness_response_pallet_info() -> Weight; + fn send_pallet_migration_for(_x: u32) -> Weight; + fn confirm_pallet_migrations(_x: u32) -> Weight; } /// Weights for `pallet_funding` using the Substrate node and recommended hardware. @@ -812,6 +821,35 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + + // TODO: add real benchmarked weights + fn start_pallet_migration() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn start_offchain_migration() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn confirm_offchain_migration(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn mark_project_ct_migration_as_finished() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn start_pallet_migration_readiness_check() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn pallet_migration_readiness_response_holding() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn pallet_migration_readiness_response_pallet_info() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn send_pallet_migration_for(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn confirm_pallet_migrations(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } } // For backwards compatibility and tests. @@ -1541,4 +1579,33 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + + // TODO: Add real benchmarked weights + fn start_pallet_migration() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn start_offchain_migration() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn confirm_offchain_migration(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn mark_project_ct_migration_as_finished() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn start_pallet_migration_readiness_check() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn pallet_migration_readiness_response_holding() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn pallet_migration_readiness_response_pallet_info() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn send_pallet_migration_for(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn confirm_pallet_migrations(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } } \ No newline at end of file diff --git a/polimec-common/common/src/lib.rs b/polimec-common/common/src/lib.rs index 6553b56fa..6c302958d 100644 --- a/polimec-common/common/src/lib.rs +++ b/polimec-common/common/src/lib.rs @@ -19,6 +19,8 @@ use frame_support::{pallet_prelude::*, traits::tokens::fungible}; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; +use xcm::v3::{opaque::Xcm, MultiAssets, MultiLocation, SendError, SendResult, SendXcm, XcmHash}; + pub mod credentials; /// A release schedule over a fungible. This allows a particular fungible to have release limits @@ -215,3 +217,17 @@ pub mod migration_types { pub const USD_DECIMALS: u8 = 6; pub const USD_UNIT: u128 = 10u128.pow(USD_DECIMALS as u32); + +pub struct DummyXcmSender; +impl SendXcm for DummyXcmSender { + type Ticket = (); + + fn validate(_: &mut Option, _: &mut Option) -> SendResult { + Ok(((), MultiAssets::new())) + } + + /// Actually carry out the delivery operation for a previously validated message sending. + fn deliver(_ticket: Self::Ticket) -> Result { + Ok([0u8; 32]) + } +} diff --git a/runtimes/polimec/src/weights/pallet_funding.rs b/runtimes/polimec/src/weights/pallet_funding.rs index a0515d393..b6fcc460e 100644 --- a/runtimes/polimec/src/weights/pallet_funding.rs +++ b/runtimes/polimec/src/weights/pallet_funding.rs @@ -761,4 +761,33 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + + // TODO: Add real benchmarked weights + fn start_pallet_migration() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn start_offchain_migration() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn confirm_offchain_migration(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn mark_project_ct_migration_as_finished() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn start_pallet_migration_readiness_check() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn pallet_migration_readiness_response_holding() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn pallet_migration_readiness_response_pallet_info() -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn send_pallet_migration_for(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } + fn confirm_pallet_migrations(_x: u32) -> Weight { + Weight::from_parts(100_000, 10_000) + } } \ No newline at end of file diff --git a/runtimes/polimec/src/xcm_config.rs b/runtimes/polimec/src/xcm_config.rs index a2581a8a9..e1fe4c95b 100644 --- a/runtimes/polimec/src/xcm_config.rs +++ b/runtimes/polimec/src/xcm_config.rs @@ -26,6 +26,8 @@ use frame_support::{ weights::Weight, }; use pallet_xcm::XcmPassthrough; +#[cfg(feature = "runtime-benchmarks")] +use polimec_common::DummyXcmSender; use polimec_xcm_executor::{ polimec_traits::{JustTry, Properties, ShouldExecute}, XcmExecutor, @@ -308,12 +310,15 @@ pub type LocalOriginToLocation = SignedToAccountId32, // ..and XCMP to communicate with the sibling chains. XcmpQueue, ); +#[cfg(feature = "runtime-benchmarks")] +pub type XcmRouter = DummyXcmSender; /// Conservative weight values for XCM extrinsics. Should eventually be adjusted by benchmarking. pub struct XcmWeightInfo; diff --git a/runtimes/shared-configuration/src/currency.rs b/runtimes/shared-configuration/src/currency.rs index 766117822..9900bc242 100644 --- a/runtimes/shared-configuration/src/currency.rs +++ b/runtimes/shared-configuration/src/currency.rs @@ -26,7 +26,6 @@ pub const PLMC: Balance = 10u128.pow(10); /// 0.001 PLMC pub const MILLI_PLMC: Balance = 10u128.pow(7); - /// 0.000_001 PLMC pub const MICRO_PLMC: Balance = 10u128.pow(4);