diff --git a/justfile b/justfile index c9d44c77d..24ef86e67 100644 --- a/justfile +++ b/justfile @@ -29,6 +29,14 @@ dry-run-benchmarks: --pallet="*" \ --extrinsic=* \ --wasm-execution=compiled \ + --heap-pages=4096 && \ + cargo run --features runtime-benchmarks --release -p polimec-node benchmark pallet \ + --chain=polimec-local \ + --steps=2 \ + --repeat=1 \ + --pallet="*" \ + --extrinsic=* \ + --wasm-execution=compiled \ --heap-pages=4096 # src: https://github.com/polkadot-fellows/runtimes/blob/48ccfae6141d2924f579d81e8b1877efd208693f/system-parachains/asset-hubs/asset-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index 4c57ca4a4..3f6f3f1c9 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -121,7 +121,7 @@ pub use crate::weights::WeightInfo; use frame_support::{ traits::{ tokens::{fungible, fungibles, Balance}, - AccountTouch, ContainsPair, Randomness, + AccountTouch, ContainsPair, Randomness, StorageVersion, }, BoundedVec, PalletId, }; @@ -154,6 +154,7 @@ pub mod tests; pub mod benchmarking; #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] pub mod instantiator; +pub mod migration; pub mod traits; pub type AccountIdOf = ::AccountId; @@ -213,6 +214,7 @@ pub mod pallet { } #[pallet::pallet] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] diff --git a/pallets/funding/src/migration.rs b/pallets/funding/src/migration.rs new file mode 100644 index 000000000..76045faa4 --- /dev/null +++ b/pallets/funding/src/migration.rs @@ -0,0 +1,209 @@ +//! A module that is responsible for migration of storage. + +use crate::{ + types::{HRMPChannelStatus, MigrationReadinessCheck, PhaseTransitionPoints, ProjectStatus}, + AccountIdOf, BalanceOf, BlockNumberFor, Config, Did, EvaluationRoundInfoOf, Pallet, PriceOf, ProjectId, +}; +use frame_support::{ + pallet_prelude::*, + traits::{tokens::Balance as BalanceT, OnRuntimeUpgrade, StorageVersion}, + weights::Weight, +}; +use parity_scale_codec::{Decode, Encode}; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use sp_arithmetic::FixedPointNumber; +use sp_std::marker::PhantomData; + +/// The current storage version +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); +pub const LOG: &str = "runtime::funding::migration"; + +mod v0 { + use super::*; + pub use cleaner::*; + mod cleaner { + use super::*; + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct Success; + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct Failure; + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub enum CleanerState { + Initialized(PhantomData), + // Success or Failure + EvaluationRewardOrSlash(u64, PhantomData), + EvaluationUnbonding(u64, PhantomData), + // Branch + // A. Success only + BidCTMint(u64, PhantomData), + ContributionCTMint(u64, PhantomData), + StartBidderVestingSchedule(u64, PhantomData), + StartContributorVestingSchedule(u64, PhantomData), + BidFundingPayout(u64, PhantomData), + ContributionFundingPayout(u64, PhantomData), + // B. Failure only + BidFundingRelease(u64, PhantomData), + BidUnbonding(u64, PhantomData), + ContributionFundingRelease(u64, PhantomData), + ContributionUnbonding(u64, PhantomData), + // Merge + // Success or Failure + Finished(PhantomData), + } + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub enum Cleaner { + NotReady, + Success(CleanerState), + Failure(CleanerState), + } + impl TryFrom for Cleaner { + type Error = (); + + fn try_from(value: ProjectStatus) -> Result { + match value { + ProjectStatus::FundingSuccessful => Ok(Cleaner::Success(CleanerState::Initialized(PhantomData))), + ProjectStatus::FundingFailed | ProjectStatus::EvaluationFailed => + Ok(Cleaner::Failure(CleanerState::Initialized(PhantomData))), + _ => Err(()), + } + } + } + } + + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] + pub struct ProjectDetails< + AccountId, + Did, + BlockNumber, + Price: FixedPointNumber, + Balance: BalanceT, + EvaluationRoundInfo, + > { + pub issuer_account: AccountId, + pub issuer_did: Did, + /// Whether the project is frozen, so no `metadata` changes are allowed. + pub is_frozen: bool, + /// The price in USD per token decided after the Auction Round + pub weighted_average_price: Option, + /// The current status of the project + pub status: ProjectStatus, + /// When the different project phases start and end + pub phase_transition_points: PhaseTransitionPoints, + /// Fundraising target amount in USD equivalent + pub fundraising_target: Balance, + /// The amount of Contribution Tokens that have not yet been sold + pub remaining_contribution_tokens: Balance, + /// Funding reached amount in USD equivalent + pub funding_amount_reached: Balance, + /// Cleanup operations remaining + pub cleanup: Cleaner, + /// Information about the total amount bonded, and the outcome in regards to reward/slash/nothing + pub evaluation_round_info: EvaluationRoundInfo, + /// When the Funding Round ends + pub funding_end_block: Option, + /// ParaId of project + pub parachain_id: Option, + /// Migration readiness check + pub migration_readiness_check: Option, + /// HRMP Channel status + pub hrmp_channel_status: HRMPChannelStatus, + } + pub type ProjectDetailsOf = + ProjectDetails, Did, BlockNumberFor, PriceOf, BalanceOf, EvaluationRoundInfoOf>; + + #[frame_support::storage_alias] + pub(crate) type ProjectsDetails = + StorageMap, Blake2_128Concat, ProjectId, ProjectDetailsOf>; +} + +pub mod v1 { + use super::*; + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] + pub struct ProjectDetails< + AccountId, + Did, + BlockNumber, + Price: FixedPointNumber, + Balance: BalanceT, + EvaluationRoundInfo, + > { + pub issuer_account: AccountId, + pub issuer_did: Did, + /// Whether the project is frozen, so no `metadata` changes are allowed. + pub is_frozen: bool, + /// The price in USD per token decided after the Auction Round + pub weighted_average_price: Option, + /// The current status of the project + pub status: ProjectStatus, + /// When the different project phases start and end + pub phase_transition_points: PhaseTransitionPoints, + /// Fundraising target amount in USD equivalent + pub fundraising_target: Balance, + /// The amount of Contribution Tokens that have not yet been sold + pub remaining_contribution_tokens: Balance, + /// Funding reached amount in USD equivalent + pub funding_amount_reached: Balance, + /// Information about the total amount bonded, and the outcome in regards to reward/slash/nothing + pub evaluation_round_info: EvaluationRoundInfo, + /// When the Funding Round ends + pub funding_end_block: Option, + /// ParaId of project + pub parachain_id: Option, + /// Migration readiness check + pub migration_readiness_check: Option, + /// HRMP Channel status + pub hrmp_channel_status: HRMPChannelStatus, + } + pub type ProjectDetailsOf = + ProjectDetails, Did, BlockNumberFor, PriceOf, BalanceOf, EvaluationRoundInfoOf>; + + #[frame_support::storage_alias] + pub(crate) type ProjectsDetails = + StorageMap, Blake2_128Concat, ProjectId, ProjectDetailsOf>; + + /// Migrates `ProjectDetails` from v0 to v1. + pub struct UncheckedMigrationToV1(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for UncheckedMigrationToV1 { + #[allow(deprecated)] + fn on_runtime_upgrade() -> Weight { + // cleaner field does not exist anymore so we ignore it + let mut storage_translations = 0u64; + let mut translate = |pre: v0::ProjectDetailsOf| -> Option> { + storage_translations += 1; + Some(v1::ProjectDetailsOf:: { + issuer_account: pre.issuer_account, + issuer_did: pre.issuer_did, + is_frozen: pre.is_frozen, + weighted_average_price: pre.weighted_average_price, + status: pre.status, + phase_transition_points: pre.phase_transition_points, + fundraising_target: pre.fundraising_target, + remaining_contribution_tokens: pre.remaining_contribution_tokens, + funding_amount_reached: pre.funding_amount_reached, + evaluation_round_info: pre.evaluation_round_info, + funding_end_block: pre.funding_end_block, + parachain_id: pre.parachain_id, + migration_readiness_check: pre.migration_readiness_check, + hrmp_channel_status: pre.hrmp_channel_status, + }) + }; + + v1::ProjectsDetails::::translate(|_key, pre: v0::ProjectDetailsOf| translate(pre)); + + T::DbWeight::get().reads_writes(storage_translations, storage_translations) + } + } + + /// [`UncheckedMigrationToV1`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. + #[allow(dead_code)] + pub type MigrationToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + UncheckedMigrationToV1, + Pallet, + ::DbWeight, + >; +} diff --git a/runtimes/politest/src/lib.rs b/runtimes/politest/src/lib.rs index 8428642dd..6f15f0f35 100644 --- a/runtimes/politest/src/lib.rs +++ b/runtimes/politest/src/lib.rs @@ -163,7 +163,7 @@ pub type Migrations = migrations::Unreleased; pub mod migrations { // use crate::Runtime; /// Unreleased migrations. Add new ones here: - pub type Unreleased = (); + pub type Unreleased = pallet_funding::migration::v1::MigrationToV1; } /// Executive: handles dispatch to the various modules. @@ -209,7 +209,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("politest"), impl_name: create_runtime_str!("politest"), authoring_version: 1, - spec_version: 0_006_000, + spec_version: 0_006_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2,