diff --git a/primitives/src/market.rs b/primitives/src/market.rs index 02f3972ad..cae1eb2bc 100644 --- a/primitives/src/market.rs +++ b/primitives/src/market.rs @@ -343,19 +343,6 @@ pub enum ResolutionMechanism { Noop, } -/// Contains a market id and the market period. -/// -/// * `BN`: Block Number -/// * `MO`: Moment (Time moment) -/// * `MI`: Market Id -#[derive(TypeInfo, Clone, Eq, PartialEq, Decode, Encode, MaxEncodedLen, RuntimeDebug)] -pub struct SubsidyUntil { - /// Market id of associated market. - pub market_id: MI, - /// Market start and end. - pub period: MarketPeriod, -} - #[cfg(test)] mod tests { use crate::{market::*, types::Asset}; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 430ea89cc..12e5a57cb 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -55,23 +55,12 @@ macro_rules! decl_common_types { use orml_traits::MultiCurrency; use sp_runtime::{generic, DispatchError, DispatchResult, SaturatedConversion}; use zeitgeist_primitives::traits::{DeployPoolApi, DistributeFees, MarketCommonsPalletApi}; - use zrml_market_commons::migrations::MigrateScoringRuleAndMarketStatus; - use zrml_neo_swaps::migration::MigrateToLiquidityTree; - use zrml_orderbook::migrations::TranslateOrderStructure; - use zrml_prediction_markets::migrations::DrainDeprecatedStorage; - use zrml_swaps::migrations::MigratePools; pub type Block = generic::Block; type Address = sp_runtime::MultiAddress; - type Migrations = ( - MigratePools, - DrainDeprecatedStorage, - MigrateScoringRuleAndMarketStatus, - TranslateOrderStructure, - MigrateToLiquidityTree, - ); + type Migrations = (); pub type Executive = frame_executive::Executive< Runtime, diff --git a/zrml/market-commons/src/migrations.rs b/zrml/market-commons/src/migrations.rs index 95890edb8..7bcc6e2e5 100644 --- a/zrml/market-commons/src/migrations.rs +++ b/zrml/market-commons/src/migrations.rs @@ -15,478 +15,3 @@ // // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . - -use crate::{ - AccountIdOf, AssetOf, BalanceOf, BlockNumberOf, Config, MarketIdOf, MomentOf, - Pallet as MarketCommons, -}; -use alloc::vec::Vec; -use core::marker::PhantomData; -use frame_support::{ - log, - pallet_prelude::{Blake2_128Concat, StorageVersion, Weight}, - traits::{Get, OnRuntimeUpgrade}, -}; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::{Perbill, RuntimeDebug, Saturating}; -use zeitgeist_primitives::types::{ - Deadlines, EarlyClose, Market, MarketBonds, MarketCreation, MarketDisputeMechanism, - MarketPeriod, MarketStatus, MarketType, OutcomeReport, Report, ScoringRule, -}; - -#[cfg(feature = "try-runtime")] -use { - alloc::collections::BTreeMap, frame_support::migration::storage_key_iter, - zeitgeist_primitives::types::MarketId, -}; - -#[cfg(any(feature = "try-runtime", test))] -const MARKET_COMMONS: &[u8] = b"MarketCommons"; -#[cfg(any(feature = "try-runtime", test))] -const MARKETS: &[u8] = b"Markets"; - -#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct OldMarket { - pub base_asset: A, - pub creator: AI, - pub creation: MarketCreation, - pub creator_fee: Perbill, - pub oracle: AI, - pub metadata: Vec, - pub market_type: MarketType, - pub period: MarketPeriod, - pub deadlines: Deadlines, - pub scoring_rule: OldScoringRule, - pub status: OldMarketStatus, - pub report: Option>, - pub resolved_outcome: Option, - pub dispute_mechanism: Option, - pub bonds: MarketBonds, - pub early_close: Option>, -} - -type OldMarketOf = - OldMarket, BalanceOf, BlockNumberOf, MomentOf, AssetOf>; - -#[derive(TypeInfo, Clone, Copy, Encode, Eq, Decode, MaxEncodedLen, PartialEq, RuntimeDebug)] -pub enum OldScoringRule { - CPMM, - RikiddoSigmoidFeeMarketEma, - Lmsr, - Orderbook, - Parimutuel, -} - -#[derive(Clone, Copy, Decode, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] -pub enum OldMarketStatus { - Proposed, - Active, - Suspended, - Closed, - CollectingSubsidy, - InsufficientSubsidy, - Reported, - Disputed, - Resolved, -} - -const MARKET_COMMONS_REQUIRED_STORAGE_VERSION: u16 = 9; -const MARKET_COMMONS_NEXT_STORAGE_VERSION: u16 = 10; - -#[frame_support::storage_alias] -pub(crate) type Markets = - StorageMap, Blake2_128Concat, MarketIdOf, OldMarketOf>; - -pub struct MigrateScoringRuleAndMarketStatus(PhantomData); - -/// Deletes all Rikiddo markets from storage and migrates CPMM markets to LMSR. -impl OnRuntimeUpgrade for MigrateScoringRuleAndMarketStatus -where - T: Config, -{ - fn on_runtime_upgrade() -> Weight { - let mut total_weight = T::DbWeight::get().reads(1); - let market_commons_version = StorageVersion::get::>(); - if market_commons_version != MARKET_COMMONS_REQUIRED_STORAGE_VERSION { - log::info!( - "MigrateScoringRuleAndMarketStatus: market-commons version is {:?}, but {:?} is \ - required", - market_commons_version, - MARKET_COMMONS_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("MigrateScoringRuleAndMarketStatus: Starting..."); - - let mut translated = 0u64; - crate::Markets::::translate::, _>(|_, old_market| { - // We proceed by deleting markets which use the Rikiddo scoring rule or have a status - // that was removed. - translated.saturating_inc(); - let scoring_rule = match old_market.scoring_rule { - OldScoringRule::RikiddoSigmoidFeeMarketEma => return None, - OldScoringRule::CPMM | OldScoringRule::Lmsr => ScoringRule::Lmsr, - OldScoringRule::Orderbook => ScoringRule::Orderbook, - OldScoringRule::Parimutuel => ScoringRule::Parimutuel, - }; - let status = match old_market.status { - OldMarketStatus::Proposed => MarketStatus::Proposed, - OldMarketStatus::Active => MarketStatus::Active, - OldMarketStatus::Suspended => return None, - OldMarketStatus::Closed => MarketStatus::Closed, - OldMarketStatus::CollectingSubsidy => return None, - OldMarketStatus::InsufficientSubsidy => return None, - OldMarketStatus::Reported => MarketStatus::Reported, - OldMarketStatus::Disputed => MarketStatus::Disputed, - OldMarketStatus::Resolved => MarketStatus::Resolved, - }; - let new_market = Market { - base_asset: old_market.base_asset, - creator: old_market.creator, - creation: old_market.creation, - creator_fee: old_market.creator_fee, - oracle: old_market.oracle, - metadata: old_market.metadata, - market_type: old_market.market_type, - period: old_market.period, - deadlines: old_market.deadlines, - scoring_rule, - status, - report: old_market.report, - resolved_outcome: old_market.resolved_outcome, - dispute_mechanism: old_market.dispute_mechanism, - bonds: old_market.bonds, - early_close: old_market.early_close, - }; - Some(new_market) - }); - log::info!("MigrateScoringRuleAndMarketStatus: Upgraded {} markets.", translated); - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(translated, translated)); - - StorageVersion::new(MARKET_COMMONS_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("MigrateScoringRuleAndMarketStatus: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - let old_markets = storage_key_iter::, OldMarketOf, Blake2_128Concat>( - MARKET_COMMONS, - MARKETS, - ) - .collect::>(); - let markets = Markets::::iter_keys().count(); - let decodable_markets = Markets::::iter_values().count(); - if markets == decodable_markets { - log::info!("All {} markets could successfully be decoded.", markets); - } else { - log::error!( - "Can only decode {} of {} markets - others will be dropped.", - decodable_markets, - markets - ); - } - - Ok(old_markets.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { - let old_markets: BTreeMap> = - Decode::decode(&mut &previous_state[..]).unwrap(); - let old_market_count = old_markets.len(); - let new_market_count = Markets::::iter().count(); - assert_eq!(old_market_count, new_market_count); - log::info!( - "MigrateScoringRuleAndMarketStatus: Market counter post-upgrade is {}!", - new_market_count - ); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{ExtBuilder, Runtime}; - use alloc::fmt::Debug; - use frame_support::{migration::put_storage_value, storage_root, StorageHasher}; - use sp_runtime::{Perbill, StateVersion}; - use test_case::test_case; - use zeitgeist_primitives::types::{Asset, Bond, MarketId}; - - #[test] - fn on_runtime_upgrade_increments_the_storage_version() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - MigrateScoringRuleAndMarketStatus::::on_runtime_upgrade(); - assert_eq!( - StorageVersion::get::>(), - MARKET_COMMONS_NEXT_STORAGE_VERSION - ); - }); - } - - #[test_case( - (OldScoringRule::CPMM, OldMarketStatus::Proposed), - Some((ScoringRule::Lmsr, MarketStatus::Proposed)) - )] - #[test_case( - (OldScoringRule::CPMM, OldMarketStatus::Active), - Some((ScoringRule::Lmsr, MarketStatus::Active)) - )] - #[test_case((OldScoringRule::CPMM, OldMarketStatus::Suspended), None)] - #[test_case( - (OldScoringRule::CPMM, OldMarketStatus::Closed), - Some((ScoringRule::Lmsr, MarketStatus::Closed)) - )] - #[test_case((OldScoringRule::CPMM, OldMarketStatus::CollectingSubsidy), None)] - #[test_case((OldScoringRule::CPMM, OldMarketStatus::InsufficientSubsidy), None)] - #[test_case( - (OldScoringRule::CPMM, OldMarketStatus::Reported), - Some((ScoringRule::Lmsr, MarketStatus::Reported)) - )] - #[test_case( - (OldScoringRule::CPMM, OldMarketStatus::Disputed), - Some((ScoringRule::Lmsr, MarketStatus::Disputed)) - )] - #[test_case( - (OldScoringRule::CPMM, OldMarketStatus::Resolved), - Some((ScoringRule::Lmsr, MarketStatus::Resolved)) - )] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Proposed), None)] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Active), None)] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Suspended), None)] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Closed), None)] - #[test_case( - (OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::CollectingSubsidy), - None - )] - #[test_case( - (OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::InsufficientSubsidy), - None - )] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Reported), None)] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Disputed), None)] - #[test_case((OldScoringRule::RikiddoSigmoidFeeMarketEma, OldMarketStatus::Resolved), None)] - #[test_case( - (OldScoringRule::Lmsr, OldMarketStatus::Proposed), - Some((ScoringRule::Lmsr, MarketStatus::Proposed)) - )] - #[test_case( - (OldScoringRule::Lmsr, OldMarketStatus::Active), - Some((ScoringRule::Lmsr, MarketStatus::Active)) - )] - #[test_case((OldScoringRule::Lmsr, OldMarketStatus::Suspended), None)] - #[test_case( - (OldScoringRule::Lmsr, OldMarketStatus::Closed), - Some((ScoringRule::Lmsr, MarketStatus::Closed)) - )] - #[test_case((OldScoringRule::Lmsr, OldMarketStatus::CollectingSubsidy), None)] - #[test_case((OldScoringRule::Lmsr, OldMarketStatus::InsufficientSubsidy), None)] - #[test_case( - (OldScoringRule::Lmsr, OldMarketStatus::Reported), - Some((ScoringRule::Lmsr, MarketStatus::Reported)) - )] - #[test_case( - (OldScoringRule::Lmsr, OldMarketStatus::Disputed), - Some((ScoringRule::Lmsr, MarketStatus::Disputed)) - )] - #[test_case( - (OldScoringRule::Lmsr, OldMarketStatus::Resolved), - Some((ScoringRule::Lmsr, MarketStatus::Resolved)) - )] - #[test_case( - (OldScoringRule::Orderbook, OldMarketStatus::Proposed), - Some((ScoringRule::Orderbook, MarketStatus::Proposed)) - )] - #[test_case( - (OldScoringRule::Orderbook, OldMarketStatus::Active), - Some((ScoringRule::Orderbook, MarketStatus::Active)) - )] - #[test_case((OldScoringRule::Orderbook, OldMarketStatus::Suspended), None)] - #[test_case( - (OldScoringRule::Orderbook, OldMarketStatus::Closed), - Some((ScoringRule::Orderbook, MarketStatus::Closed)) - )] - #[test_case((OldScoringRule::Orderbook, OldMarketStatus::CollectingSubsidy), None)] - #[test_case((OldScoringRule::Orderbook, OldMarketStatus::InsufficientSubsidy), None)] - #[test_case( - (OldScoringRule::Orderbook, OldMarketStatus::Reported), - Some((ScoringRule::Orderbook, MarketStatus::Reported)) - )] - #[test_case( - (OldScoringRule::Orderbook, OldMarketStatus::Disputed), - Some((ScoringRule::Orderbook, MarketStatus::Disputed)) - )] - #[test_case( - (OldScoringRule::Orderbook, OldMarketStatus::Resolved), - Some((ScoringRule::Orderbook, MarketStatus::Resolved)) - )] - #[test_case( - (OldScoringRule::Parimutuel, OldMarketStatus::Proposed), - Some((ScoringRule::Parimutuel, MarketStatus::Proposed)) - )] - #[test_case( - (OldScoringRule::Parimutuel, OldMarketStatus::Active), - Some((ScoringRule::Parimutuel, MarketStatus::Active)) - )] - #[test_case((OldScoringRule::Parimutuel, OldMarketStatus::Suspended), None)] - #[test_case( - (OldScoringRule::Parimutuel, OldMarketStatus::Closed), - Some((ScoringRule::Parimutuel, MarketStatus::Closed)) - )] - #[test_case((OldScoringRule::Parimutuel, OldMarketStatus::CollectingSubsidy), None)] - #[test_case((OldScoringRule::Parimutuel, OldMarketStatus::InsufficientSubsidy), None)] - #[test_case( - (OldScoringRule::Parimutuel, OldMarketStatus::Reported), - Some((ScoringRule::Parimutuel, MarketStatus::Reported)) - )] - #[test_case( - (OldScoringRule::Parimutuel, OldMarketStatus::Disputed), - Some((ScoringRule::Parimutuel, MarketStatus::Disputed)) - )] - #[test_case( - (OldScoringRule::Parimutuel, OldMarketStatus::Resolved), - Some((ScoringRule::Parimutuel, MarketStatus::Resolved)) - )] - fn on_runtime_upgrade_works_as_expected( - old_data: (OldScoringRule, OldMarketStatus), - new_data: Option<(ScoringRule, MarketStatus)>, - ) { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let base_asset = Asset::Ztg; - let creator = 0; - let creation = MarketCreation::Permissionless; - let creator_fee = Perbill::from_rational(1u32, 1_000u32); - let oracle = 2; - let metadata = vec![0x03; 50]; - let market_type = MarketType::Categorical(4); - let period = MarketPeriod::Block(5..6); - let deadlines = Deadlines { grace_period: 7, oracle_duration: 8, dispute_duration: 9 }; - let report = Some(Report { at: 13, by: 14, outcome: OutcomeReport::Categorical(10) }); - let resolved_outcome = None; - let dispute_mechanism = Some(MarketDisputeMechanism::Court); - let bonds = MarketBonds { - creation: Some(Bond::new(11, 12)), - oracle: None, - outsider: None, - dispute: None, - close_dispute: None, - close_request: None, - }; - let early_close = None; - let (old_scoring_rule, old_market_status) = old_data; - let old_market = OldMarket { - base_asset, - creator, - creation: creation.clone(), - creator_fee, - oracle, - metadata: metadata.clone(), - market_type: market_type.clone(), - period: period.clone(), - deadlines, - scoring_rule: old_scoring_rule, - status: old_market_status, - report: report.clone(), - resolved_outcome: resolved_outcome.clone(), - dispute_mechanism: dispute_mechanism.clone(), - bonds: bonds.clone(), - early_close: early_close.clone(), - }; - let opt_new_market = if let Some((new_scoring_rule, new_status)) = new_data { - Some(Market { - base_asset, - creator, - creation, - creator_fee, - oracle, - metadata, - market_type, - period, - deadlines, - scoring_rule: new_scoring_rule, - status: new_status, - report, - resolved_outcome, - dispute_mechanism, - bonds, - early_close, - }) - } else { - None - }; - // Don't set up chain to signal that storage is already up to date. - populate_test_data::>( - MARKET_COMMONS, - MARKETS, - vec![old_market], - ); - MigrateScoringRuleAndMarketStatus::::on_runtime_upgrade(); - - let actual = crate::Markets::::get(0); - assert_eq!(actual, opt_new_market); - }); - } - - #[test] - fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - StorageVersion::new(MARKET_COMMONS_NEXT_STORAGE_VERSION) - .put::>(); - let market = Market { - base_asset: Asset::>::ForeignAsset(0), - creator: 1, - creation: MarketCreation::Permissionless, - creator_fee: Perbill::from_rational(2u32, 3u32), - oracle: 4, - metadata: vec![0x05; 50], - market_type: MarketType::Categorical(999), - period: MarketPeriod::, MomentOf>::Block(6..7), - deadlines: Deadlines { grace_period: 7, oracle_duration: 8, dispute_duration: 9 }, - scoring_rule: ScoringRule::Parimutuel, - status: MarketStatus::Active, - report: Some(Report { at: 13, by: 14, outcome: OutcomeReport::Categorical(10) }), - resolved_outcome: None, - dispute_mechanism: Some(MarketDisputeMechanism::Court), - bonds: MarketBonds { - creation: Some(Bond::new(11, 12)), - oracle: None, - outsider: None, - dispute: None, - close_dispute: None, - close_request: None, - }, - early_close: None, - }; - crate::Markets::::insert(333, market); - let tmp = storage_root(StateVersion::V1); - MigrateScoringRuleAndMarketStatus::::on_runtime_upgrade(); - assert_eq!(tmp, storage_root(StateVersion::V1)); - }); - } - - fn set_up_version() { - StorageVersion::new(MARKET_COMMONS_REQUIRED_STORAGE_VERSION) - .put::>(); - } - - #[allow(unused)] - fn populate_test_data(pallet: &[u8], prefix: &[u8], data: Vec) - where - H: StorageHasher, - K: TryFrom + Encode, - V: Encode + Clone, - >::Error: Debug, - { - for (key, value) in data.iter().enumerate() { - let storage_hash = K::try_from(key).unwrap().using_encoded(H::hash).as_ref().to_vec(); - put_storage_value::(pallet, prefix, &storage_hash, (*value).clone()); - } - } -} diff --git a/zrml/neo-swaps/src/migration.rs b/zrml/neo-swaps/src/migration.rs index ac04b7ce7..fb9ed7fb7 100644 --- a/zrml/neo-swaps/src/migration.rs +++ b/zrml/neo-swaps/src/migration.rs @@ -15,229 +15,6 @@ // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . -use crate::{ - liquidity_tree::types::LiquidityTree, - types::{Pool, SoloLp}, - Config, Pallet, -}; -use frame_support::{ - dispatch::Weight, - log, - pallet_prelude::PhantomData, - traits::{Get, OnRuntimeUpgrade, StorageVersion}, -}; -use sp_runtime::traits::Saturating; - -cfg_if::cfg_if! { - if #[cfg(feature = "try-runtime")] { - use crate::{MarketIdOf, Pools}; - use alloc::{collections::BTreeMap, format, vec::Vec}; - use frame_support::{migration::storage_key_iter, pallet_prelude::Twox64Concat}; - use parity_scale_codec::{Decode, Encode}; - use sp_runtime::traits::Zero; - } -} - -cfg_if::cfg_if! { - if #[cfg(any(feature = "try-runtime", test))] { - const NEO_SWAPS: &[u8] = b"NeoSwaps"; - const POOLS: &[u8] = b"Pools"; - } -} - -const NEO_SWAPS_REQUIRED_STORAGE_VERSION: u16 = 0; -const NEO_SWAPS_NEXT_STORAGE_VERSION: u16 = NEO_SWAPS_REQUIRED_STORAGE_VERSION + 1; - -type OldPoolOf = Pool>; - -pub struct MigrateToLiquidityTree(PhantomData); - -impl OnRuntimeUpgrade for MigrateToLiquidityTree { - fn on_runtime_upgrade() -> Weight { - let mut total_weight = T::DbWeight::get().reads(1); - let neo_swaps_version = StorageVersion::get::>(); - if neo_swaps_version != NEO_SWAPS_REQUIRED_STORAGE_VERSION { - log::info!( - "MigrateToLiquidityTree: neo-swaps version is {:?}, but {:?} is required", - neo_swaps_version, - NEO_SWAPS_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("MigrateToLiquidityTree: Starting..."); - let mut translated = 0u64; - crate::Pools::::translate::, _>(|_, pool| { - let solo = pool.liquidity_shares_manager; - // This should never fail; if it does, then we just delete the entry. - let mut liquidity_tree = - LiquidityTree::new(solo.owner.clone(), solo.total_shares).ok()?; - liquidity_tree.nodes.get_mut(0)?.fees = solo.fees; // Can't fail. - translated.saturating_inc(); - Some(Pool { - account_id: pool.account_id, - reserves: pool.reserves, - collateral: pool.collateral, - liquidity_parameter: pool.liquidity_parameter, - liquidity_shares_manager: liquidity_tree, - swap_fee: pool.swap_fee, - }) - }); - log::info!("MigrateToLiquidityTree: Upgraded {} pools.", translated); - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(translated, translated)); - StorageVersion::new(NEO_SWAPS_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("MigrateToLiquidityTree: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - let old_pools = - storage_key_iter::, OldPoolOf, Twox64Concat>(NEO_SWAPS, POOLS) - .collect::>(); - Ok(old_pools.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { - let old_pools: BTreeMap, OldPoolOf> = - Decode::decode(&mut &previous_state[..]) - .map_err(|_| "Failed to decode state: Invalid state")?; - let new_pool_count = Pools::::iter().count(); - assert_eq!(old_pools.len(), new_pool_count); - for (market_id, new_pool) in Pools::::iter() { - let old_pool = - old_pools.get(&market_id).expect(&format!("Pool {:?} not found", market_id)[..]); - assert_eq!(new_pool.account_id, old_pool.account_id); - assert_eq!(new_pool.reserves, old_pool.reserves); - assert_eq!(new_pool.collateral, old_pool.collateral); - assert_eq!(new_pool.liquidity_parameter, old_pool.liquidity_parameter); - assert_eq!(new_pool.swap_fee, old_pool.swap_fee); - let tree = new_pool.liquidity_shares_manager; - let solo = &old_pool.liquidity_shares_manager; - assert_eq!(tree.nodes.len(), 1); - assert_eq!(tree.abandoned_nodes.len(), 0); - assert_eq!(tree.account_to_index.len(), 1); - let root = tree.nodes[0].clone(); - let account = root.account.clone(); - assert_eq!(root.account, Some(solo.owner.clone())); - assert_eq!(root.stake, solo.total_shares); - assert_eq!(root.fees, solo.fees); - assert_eq!(root.descendant_stake, Zero::zero()); - assert_eq!(root.lazy_fees, Zero::zero()); - let address = account.unwrap(); - assert_eq!(tree.account_to_index.get(&address), Some(&0)); - } - log::info!("MigrateToLiquidityTree: Post-upgrade pool count is {}!", new_pool_count); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - mock::{ExtBuilder, Runtime}, - MarketIdOf, PoolOf, Pools, - }; - use alloc::collections::BTreeMap; - use frame_support::{ - dispatch::fmt::Debug, migration::put_storage_value, storage_root, StateVersion, - StorageHasher, Twox64Concat, - }; - use parity_scale_codec::Encode; - use zeitgeist_primitives::types::Asset; - - #[test] - fn on_runtime_upgrade_increments_the_storage_version() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - MigrateToLiquidityTree::::on_runtime_upgrade(); - assert_eq!(StorageVersion::get::>(), NEO_SWAPS_NEXT_STORAGE_VERSION); - }); - } - - #[test] - fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - StorageVersion::new(NEO_SWAPS_NEXT_STORAGE_VERSION).put::>(); - let (_, new_pools) = construct_old_new_tuple(); - populate_test_data::, PoolOf>( - NEO_SWAPS, POOLS, new_pools, - ); - let tmp = storage_root(StateVersion::V1); - MigrateToLiquidityTree::::on_runtime_upgrade(); - assert_eq!(tmp, storage_root(StateVersion::V1)); - }); - } - - #[test] - fn on_runtime_upgrade_correctly_updates_markets() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let (old_pools, new_pools) = construct_old_new_tuple(); - populate_test_data::, OldPoolOf>( - NEO_SWAPS, POOLS, old_pools, - ); - MigrateToLiquidityTree::::on_runtime_upgrade(); - let actual = Pools::get(0u128).unwrap(); - assert_eq!(actual, new_pools[0]); - }); - } - - fn set_up_version() { - StorageVersion::new(NEO_SWAPS_REQUIRED_STORAGE_VERSION).put::>(); - } - - fn construct_old_new_tuple() -> (Vec>, Vec>) { - let account_id = 1; - let mut reserves = BTreeMap::new(); - reserves.insert(Asset::CategoricalOutcome(2, 3), 4); - let collateral = Asset::Ztg; - let liquidity_parameter = 5; - let swap_fee = 6; - let total_shares = 7; - let fees = 8; - - let solo = SoloLp { owner: account_id, total_shares, fees }; - let mut liquidity_tree = LiquidityTree::new(account_id, total_shares).unwrap(); - liquidity_tree.nodes.get_mut(0).unwrap().fees = fees; - - let old_pool = OldPoolOf { - account_id, - reserves: reserves.clone(), - collateral, - liquidity_parameter, - liquidity_shares_manager: solo, - swap_fee, - }; - let new_pool = Pool { - account_id, - reserves, - collateral, - liquidity_parameter, - liquidity_shares_manager: liquidity_tree, - swap_fee, - }; - (vec![old_pool], vec![new_pool]) - } - - #[allow(unused)] - fn populate_test_data(pallet: &[u8], prefix: &[u8], data: Vec) - where - H: StorageHasher, - K: TryFrom + Encode, - V: Encode + Clone, - >::Error: Debug, - { - for (key, value) in data.iter().enumerate() { - let storage_hash = utility::key_to_hash::(K::try_from(key).unwrap()); - put_storage_value::(pallet, prefix, &storage_hash, (*value).clone()); - } - } -} - mod utility { use alloc::vec::Vec; use frame_support::StorageHasher; diff --git a/zrml/neo-swaps/src/types/mod.rs b/zrml/neo-swaps/src/types/mod.rs index 3968b4718..30734e23e 100644 --- a/zrml/neo-swaps/src/types/mod.rs +++ b/zrml/neo-swaps/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Forecasting Technologies LTD. +// Copyright 2023-2024 Forecasting Technologies LTD. // // This file is part of Zeitgeist. // @@ -17,8 +17,6 @@ mod fee_distribution; mod pool; -mod solo_lp; pub(crate) use fee_distribution::*; pub(crate) use pool::*; -pub(crate) use solo_lp::*; diff --git a/zrml/neo-swaps/src/types/solo_lp.rs b/zrml/neo-swaps/src/types/solo_lp.rs deleted file mode 100644 index 503a72bbe..000000000 --- a/zrml/neo-swaps/src/types/solo_lp.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2023-2024 Forecasting Technologies LTD. -// -// This file is part of Zeitgeist. -// -// Zeitgeist is free software: you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the -// Free Software Foundation, either version 3 of the License, or (at -// your option) any later version. -// -// Zeitgeist is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Zeitgeist. If not, see . - -// TODO(#1212): Remove in v0.5.1. - -use crate::{traits::LiquiditySharesManager, BalanceOf, Config, Error}; -use frame_support::ensure; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Zero}, - DispatchError, DispatchResult, RuntimeDebug, -}; - -#[derive(TypeInfo, MaxEncodedLen, Clone, Encode, Eq, Decode, PartialEq, RuntimeDebug)] -#[scale_info(skip_type_params(T))] -pub struct SoloLp { - pub owner: T::AccountId, - pub total_shares: BalanceOf, - pub fees: BalanceOf, -} - -#[allow(dead_code)] -impl SoloLp { - pub(crate) fn new(owner: T::AccountId, total_shares: BalanceOf) -> SoloLp { - SoloLp { owner, total_shares, fees: Zero::zero() } - } -} - -impl LiquiditySharesManager for SoloLp -where - T::AccountId: PartialEq, - BalanceOf: AtLeast32BitUnsigned + Copy + Zero, -{ - type JoinBenchmarkInfo = (); - - fn join(&mut self, who: &T::AccountId, shares: BalanceOf) -> Result<(), DispatchError> { - ensure!(*who == self.owner, Error::::NotAllowed); - self.total_shares = self.total_shares.checked_add(&shares).ok_or(Error::::MathError)?; - Ok(()) - } - - fn exit(&mut self, who: &T::AccountId, shares: BalanceOf) -> DispatchResult { - ensure!(*who == self.owner, Error::::NotAllowed); - ensure!(shares <= self.total_shares, Error::::InsufficientPoolShares); - self.total_shares = self.total_shares.checked_sub(&shares).ok_or(Error::::MathError)?; - Ok(()) - } - - fn split( - &mut self, - _sender: &T::AccountId, - _receiver: &T::AccountId, - _amount: BalanceOf, - ) -> DispatchResult { - Err(Error::::NotImplemented.into()) - } - - fn deposit_fees(&mut self, amount: BalanceOf) -> DispatchResult { - self.fees = self.fees.checked_add(&amount).ok_or(Error::::MathError)?; - Ok(()) - } - - fn withdraw_fees(&mut self, who: &T::AccountId) -> Result, DispatchError> { - ensure!(*who == self.owner, Error::::NotAllowed); - let result = self.fees; - self.fees = Zero::zero(); - Ok(result) - } - - fn shares_of(&self, who: &T::AccountId) -> Result, DispatchError> { - ensure!(*who == self.owner, Error::::NotAllowed); - Ok(self.total_shares) - } - - fn total_shares(&self) -> Result, DispatchError> { - Ok(self.total_shares) - } -} diff --git a/zrml/orderbook/src/migrations.rs b/zrml/orderbook/src/migrations.rs index aa7be090a..2e9ba478f 100644 --- a/zrml/orderbook/src/migrations.rs +++ b/zrml/orderbook/src/migrations.rs @@ -1,4 +1,4 @@ -// Copyright 2023 Forecasting Technologies LTD. +// Copyright 2023-2024 Forecasting Technologies LTD. // // This file is part of Zeitgeist. // @@ -14,318 +14,3 @@ // // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . - -use crate::{ - types::{Order, OrderId}, - AccountIdOf, BalanceOf, Config, MarketIdOf, Pallet as OrderbookPallet, -}; -#[cfg(feature = "try-runtime")] -use alloc::collections::BTreeMap; -#[cfg(feature = "try-runtime")] -use alloc::format; -#[cfg(feature = "try-runtime")] -use alloc::vec::Vec; -#[cfg(feature = "try-runtime")] -use frame_support::migration::storage_key_iter; -use frame_support::{ - dispatch::Weight, - log, - pallet_prelude::PhantomData, - traits::{Get, OnRuntimeUpgrade, StorageVersion}, - RuntimeDebug, -}; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::traits::Saturating; -use zeitgeist_primitives::types::Asset; - -#[cfg(any(feature = "try-runtime", test))] -const ORDER_BOOK: &[u8] = b"Orderbook"; -#[cfg(any(feature = "try-runtime", test))] -const ORDERS: &[u8] = b"Orders"; - -const ORDER_BOOK_REQUIRED_STORAGE_VERSION: u16 = 0; -const ORDER_BOOK_NEXT_STORAGE_VERSION: u16 = 1; - -#[derive(Clone, Encode, Eq, Decode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] -pub enum OldOrderSide { - Bid, - Ask, -} - -#[derive(Clone, Encode, Eq, Decode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] -pub struct OldOrder { - pub market_id: MarketId, - pub side: OldOrderSide, - pub maker: AccountId, - pub outcome_asset: Asset, - pub base_asset: Asset, - pub outcome_asset_amount: Balance, - pub base_asset_amount: Balance, -} - -type OldOrderOf = OldOrder, BalanceOf, MarketIdOf>; - -#[frame_support::storage_alias] -pub(crate) type Orders = - StorageMap, frame_support::Twox64Concat, OrderId, OldOrderOf>; - -pub struct TranslateOrderStructure(PhantomData); - -impl OnRuntimeUpgrade for TranslateOrderStructure { - fn on_runtime_upgrade() -> Weight { - let mut total_weight = T::DbWeight::get().reads(1); - let order_book_pallet_version = StorageVersion::get::>(); - if order_book_pallet_version != ORDER_BOOK_REQUIRED_STORAGE_VERSION { - log::info!( - "TranslateOrderStructure: order book pallet version is {:?}, but {:?} is required", - order_book_pallet_version, - ORDER_BOOK_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("TranslateOrderStructure: Starting..."); - - let mut translated = 0u64; - crate::Orders::::translate::, _>(|_order_id, old_order| { - translated.saturating_inc(); - - let (maker_asset, maker_amount, taker_asset, taker_amount) = match old_order.side { - // the maker reserved the base asset for bids - OldOrderSide::Bid => ( - old_order.base_asset, - old_order.base_asset_amount, - old_order.outcome_asset, - old_order.outcome_asset_amount, - ), - // the maker reserved the outcome asset for asks - OldOrderSide::Ask => ( - old_order.outcome_asset, - old_order.outcome_asset_amount, - old_order.base_asset, - old_order.base_asset_amount, - ), - }; - - let new_order = Order { - market_id: old_order.market_id, - maker: old_order.maker, - maker_asset, - maker_amount, - taker_asset, - taker_amount, - }; - - Some(new_order) - }); - log::info!("TranslateOrderStructure: Upgraded {} orders.", translated); - total_weight = - total_weight.saturating_add(T::DbWeight::get().reads_writes(translated, translated)); - - StorageVersion::new(ORDER_BOOK_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("TranslateOrderStructure: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - use frame_support::pallet_prelude::Twox64Concat; - - let old_orders = - storage_key_iter::, Twox64Concat>(ORDER_BOOK, ORDERS) - .collect::>(); - - let orders = Orders::::iter_keys().count() as u32; - let decodable_orders = Orders::::iter_values().count() as u32; - if orders == decodable_orders { - log::info!("All orders could successfully be decoded, order_count: {}.", orders); - } else { - log::error!( - "Can only decode {} of {} orders - others will be dropped", - decodable_orders, - orders - ); - } - - Ok(old_orders.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { - use orml_traits::NamedMultiReservableCurrency; - use zeitgeist_primitives::traits::MarketCommonsPalletApi; - - let old_orders: BTreeMap> = Decode::decode(&mut &previous_state[..]) - .expect("Failed to decode state: Invalid state"); - let mut new_order_count = 0usize; - for (order_id, new_order) in crate::Orders::::iter() { - let old_order = - old_orders.get(&order_id).expect(&format!("Order {:?} not found", order_id)[..]); - // assert old fields - assert_eq!(old_order.market_id, new_order.market_id); - assert_eq!(old_order.maker, new_order.maker); - // assert new fields - let reserved = T::AssetManager::reserved_balance_named( - &OrderbookPallet::::reserve_id(), - new_order.maker_asset, - &new_order.maker, - ); - // one reserve_id is for all orders for this maker_asset - assert!(reserved >= new_order.maker_amount); - - if let Ok(market) = T::MarketCommons::market(&new_order.market_id) { - let base_asset = market.base_asset; - if new_order.maker_asset == base_asset { - assert_eq!(new_order.maker_asset, old_order.base_asset); - assert_eq!(new_order.maker_amount, old_order.base_asset_amount); - assert_eq!(new_order.taker_amount, old_order.outcome_asset_amount); - assert_eq!(new_order.taker_asset, old_order.outcome_asset); - } else { - assert_eq!(new_order.taker_asset, base_asset); - assert_eq!(new_order.taker_asset, old_order.base_asset); - assert_eq!(new_order.taker_amount, old_order.base_asset_amount); - assert_eq!(new_order.maker_amount, old_order.outcome_asset_amount); - assert_eq!(new_order.maker_asset, old_order.outcome_asset); - } - } else { - log::error!( - "The market should be present for the order market id {:?}!", - new_order.market_id - ); - } - - new_order_count.saturating_inc(); - } - assert_eq!(old_orders.len(), new_order_count); - log::info!("TranslateOrderStructure: Order Counter post-upgrade is {}!", new_order_count); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - mock::{ExtBuilder, Runtime}, - OrderOf, - }; - use alloc::vec::Vec; - use frame_support::{ - dispatch::fmt::Debug, migration::put_storage_value, storage_root, StorageHasher, - Twox64Concat, - }; - use sp_runtime::StateVersion; - use zeitgeist_primitives::types::ScalarPosition; - - #[test] - fn on_runtime_upgrade_increments_the_storage_version() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - TranslateOrderStructure::::on_runtime_upgrade(); - assert_eq!( - StorageVersion::get::>(), - ORDER_BOOK_NEXT_STORAGE_VERSION - ); - }); - } - - #[test] - fn on_runtime_upgrade_works_as_expected() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let (old_orders, new_orders) = construct_old_new_tuple(); - populate_test_data::>( - ORDER_BOOK, - ORDERS, - old_orders.clone(), - ); - TranslateOrderStructure::::on_runtime_upgrade(); - - let actual = crate::Orders::::get(0).unwrap(); - assert_eq!(actual, new_orders[0]); - - let actual = crate::Orders::::get(1).unwrap(); - assert_eq!(actual, new_orders[1]); - }); - } - - #[test] - fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - // ensure we migrated already - StorageVersion::new(ORDER_BOOK_NEXT_STORAGE_VERSION).put::>(); - - // save current storage root - let tmp = storage_root(StateVersion::V1); - TranslateOrderStructure::::on_runtime_upgrade(); - // ensure we did not change any storage with the migration - assert_eq!(tmp, storage_root(StateVersion::V1)); - }); - } - - fn set_up_version() { - StorageVersion::new(ORDER_BOOK_REQUIRED_STORAGE_VERSION).put::>(); - } - - fn construct_old_new_tuple() -> (Vec>, Vec>) { - let market_id_0 = 0; - let outcome_asset_amount_0 = 42000; - let base_asset_amount_0 = 69000; - let old_order_0 = OldOrder { - market_id: market_id_0, - side: OldOrderSide::Bid, - maker: 1, - outcome_asset: Asset::CategoricalOutcome(market_id_0, 0u16), - base_asset: Asset::Ztg, - outcome_asset_amount: outcome_asset_amount_0, - base_asset_amount: base_asset_amount_0, - }; - let new_order_0 = Order { - market_id: market_id_0, - maker: 1, - // the maker reserved the base asset for order side bid - maker_asset: Asset::Ztg, - maker_amount: base_asset_amount_0, - taker_asset: Asset::CategoricalOutcome(market_id_0, 0u16), - taker_amount: outcome_asset_amount_0, - }; - - let market_id_1 = 1; - let outcome_asset_amount_1 = 42000; - let base_asset_amount_1 = 69000; - let old_order_1 = OldOrder { - market_id: market_id_1, - side: OldOrderSide::Ask, - maker: 1, - outcome_asset: Asset::ScalarOutcome(market_id_1, ScalarPosition::Long), - base_asset: Asset::Ztg, - outcome_asset_amount: outcome_asset_amount_1, - base_asset_amount: base_asset_amount_1, - }; - let new_order_1 = Order { - market_id: market_id_1, - maker: 1, - // the maker reserved the outcome asset for order side ask - maker_asset: Asset::ScalarOutcome(market_id_1, ScalarPosition::Long), - maker_amount: outcome_asset_amount_1, - taker_asset: Asset::Ztg, - taker_amount: base_asset_amount_1, - }; - (vec![old_order_0, old_order_1], vec![new_order_0, new_order_1]) - } - - #[allow(unused)] - fn populate_test_data(pallet: &[u8], prefix: &[u8], data: Vec) - where - H: StorageHasher, - K: TryFrom + Encode, - V: Encode + Clone, - >::Error: Debug, - { - for (key, value) in data.iter().enumerate() { - let storage_hash = K::try_from(key).unwrap().using_encoded(H::hash).as_ref().to_vec(); - put_storage_value::(pallet, prefix, &storage_hash, (*value).clone()); - } - } -} diff --git a/zrml/prediction-markets/src/lib.rs b/zrml/prediction-markets/src/lib.rs index b1144dd33..1334925db 100644 --- a/zrml/prediction-markets/src/lib.rs +++ b/zrml/prediction-markets/src/lib.rs @@ -51,7 +51,6 @@ mod pallet { }; use frame_system::{ensure_signed, pallet_prelude::OriginFor}; use sp_runtime::traits::AccountIdConversion; - use zeitgeist_primitives::types::SubsidyUntil; #[cfg(feature = "parachain")] use {orml_traits::asset_registry::Inspect, zeitgeist_primitives::types::CustomMetadata}; @@ -2011,26 +2010,6 @@ mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); - // TODO(#1212): Remove in v0.5.1. - #[pallet::storage] - pub type MarketIdsPerOpenBlock = StorageMap< - _, - Blake2_128Concat, - T::BlockNumber, - BoundedVec, CacheSize>, - ValueQuery, - >; - - // TODO(#1212): Remove in v0.5.1. - #[pallet::storage] - pub type MarketIdsPerOpenTimeFrame = StorageMap< - _, - Blake2_128Concat, - TimeFrame, - BoundedVec, CacheSize>, - ValueQuery, - >; - /// A mapping of market identifiers to the block their market ends on. #[pallet::storage] pub type MarketIdsPerCloseBlock = StorageMap< @@ -2082,17 +2061,6 @@ mod pallet { pub type MarketIdsForEdit = StorageMap<_, Twox64Concat, MarketIdOf, EditReason>; - // TODO(#1212): Remove in v0.5.1. - /// Contains a list of all markets that are currently collecting subsidy and the deadline. - // All the values are "cached" here. Results in data duplication, but speeds up the iteration - // over every market significantly (otherwise 25µs per relevant market per block). - #[pallet::storage] - pub type MarketsCollectingSubsidy = StorageValue< - _, - BoundedVec, MarketIdOf>, ConstU32<16>>, - ValueQuery, - >; - impl Pallet { impl_unreserve_bond!(unreserve_creation_bond, creation); impl_unreserve_bond!(unreserve_oracle_bond, oracle); diff --git a/zrml/prediction-markets/src/migrations.rs b/zrml/prediction-markets/src/migrations.rs index ce968a678..2893d660c 100644 --- a/zrml/prediction-markets/src/migrations.rs +++ b/zrml/prediction-markets/src/migrations.rs @@ -16,154 +16,6 @@ // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . -use crate::{ - Config, MarketIdsPerOpenBlock, MarketIdsPerOpenTimeFrame, MarketsCollectingSubsidy, - Pallet as PredictionMarkets, -}; -use core::marker::PhantomData; -use frame_support::{ - log, - pallet_prelude::{StorageVersion, Weight}, - traits::{Get, OnRuntimeUpgrade}, -}; - -#[cfg(feature = "try-runtime")] -use alloc::vec::Vec; - -const PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION: u16 = 7; -const PREDICTION_MARKETS_NEXT_STORAGE_VERSION: u16 = 8; - -pub struct DrainDeprecatedStorage(PhantomData); - -impl OnRuntimeUpgrade for DrainDeprecatedStorage -where - T: Config, -{ - fn on_runtime_upgrade() -> Weight { - let mut total_weight = T::DbWeight::get().reads(1); - let prediction_markets_version = StorageVersion::get::>(); - if prediction_markets_version != PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION { - log::info!( - "DrainDeprecatedStorage: prediction-markets version is {:?}, but {:?} is required", - prediction_markets_version, - PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("DrainDeprecatedStorage: Starting..."); - let mut reads_writes = 1u64; // For killing MarketsCollectingSubsidy - reads_writes = - reads_writes.saturating_add(MarketIdsPerOpenBlock::::drain().count() as u64); - reads_writes = - reads_writes.saturating_add(MarketIdsPerOpenTimeFrame::::drain().count() as u64); - MarketsCollectingSubsidy::::kill(); - log::info!("DrainDeprecatedStorage: Drained {} keys.", reads_writes); - total_weight = total_weight - .saturating_add(T::DbWeight::get().reads_writes(reads_writes, reads_writes)); - StorageVersion::new(PREDICTION_MARKETS_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("DrainDeprecatedStorage: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_: Vec) -> Result<(), &'static str> { - if MarketIdsPerOpenBlock::::iter().count() != 0 { - return Err("DrainDeprecatedStorage: MarketIdsPerOpenBlock is not empty!"); - } - if MarketIdsPerOpenTimeFrame::::iter().count() != 0 { - return Err("DrainDeprecatedStorage: MarketIdsPerOpenTimeFrame is not empty!"); - } - if MarketsCollectingSubsidy::::exists() { - return Err("DrainDeprecatedStorage: MarketsCollectingSubsidy still exists!"); - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - mock::{ExtBuilder, Runtime}, - CacheSize, - }; - use frame_support::{ - dispatch::fmt::Debug, migration::put_storage_value, storage_root, StorageHasher, - }; - use parity_scale_codec::Encode; - use sp_runtime::{traits::ConstU32, BoundedVec, StateVersion}; - use zeitgeist_primitives::types::{MarketPeriod, SubsidyUntil}; - - #[test] - fn on_runtime_upgrade_increments_the_storage_version() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - DrainDeprecatedStorage::::on_runtime_upgrade(); - assert_eq!( - StorageVersion::get::>(), - PREDICTION_MARKETS_NEXT_STORAGE_VERSION - ); - }); - } - - #[test] - fn on_runtime_upgrade_works() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - set_up_storage(); - DrainDeprecatedStorage::::on_runtime_upgrade(); - assert_eq!(MarketIdsPerOpenBlock::::iter().count(), 0); - assert_eq!(MarketIdsPerOpenTimeFrame::::iter().count(), 0); - assert!(!MarketsCollectingSubsidy::::exists()); - }); - } - - #[test] - fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - StorageVersion::new(PREDICTION_MARKETS_NEXT_STORAGE_VERSION) - .put::>(); - set_up_storage(); - let tmp = storage_root(StateVersion::V1); - DrainDeprecatedStorage::::on_runtime_upgrade(); - assert_eq!(tmp, storage_root(StateVersion::V1)); - }); - } - - fn set_up_version() { - StorageVersion::new(PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION) - .put::>(); - } - - fn set_up_storage() { - let market_ids_per_open_block: BoundedVec<_, CacheSize> = vec![1, 2, 3].try_into().unwrap(); - MarketIdsPerOpenBlock::::insert(1, market_ids_per_open_block); - let market_ids_per_open_time_frame: BoundedVec<_, CacheSize> = - vec![4, 5, 6].try_into().unwrap(); - MarketIdsPerOpenTimeFrame::::insert(2, market_ids_per_open_time_frame); - let subsidy_until: BoundedVec<_, ConstU32<16>> = - vec![SubsidyUntil { market_id: 7, period: MarketPeriod::Block(8..9) }] - .try_into() - .unwrap(); - MarketsCollectingSubsidy::::put(subsidy_until); - } - - #[allow(unused)] - fn populate_test_data(pallet: &[u8], prefix: &[u8], data: Vec) - where - H: StorageHasher, - K: TryFrom + Encode, - V: Encode + Clone, - >::Error: Debug, - { - for (key, value) in data.iter().enumerate() { - let storage_hash = utility::key_to_hash::(K::try_from(key).unwrap()); - put_storage_value::(pallet, prefix, &storage_hash, (*value).clone()); - } - } -} - mod utility { use alloc::vec::Vec; use frame_support::StorageHasher; diff --git a/zrml/swaps/src/lib.rs b/zrml/swaps/src/lib.rs index 64fafebad..4774d2ce6 100644 --- a/zrml/swaps/src/lib.rs +++ b/zrml/swaps/src/lib.rs @@ -60,9 +60,9 @@ mod pallet { use frame_support::{ dispatch::{DispatchResultWithPostInfo, Weight}, ensure, - pallet_prelude::{OptionQuery, StorageDoubleMap, StorageMap, StorageValue, ValueQuery}, + pallet_prelude::{OptionQuery, StorageMap, StorageValue, ValueQuery}, traits::{Get, IsType, StorageVersion}, - transactional, Blake2_128Concat, PalletError, PalletId, Parameter, Twox64Concat, + transactional, Blake2_128Concat, PalletError, PalletId, Parameter, }; use frame_system::{ensure_signed, pallet_prelude::OriginFor}; use orml_traits::MultiCurrency; @@ -718,17 +718,6 @@ mod pallet { pub(crate) type Pools = StorageMap<_, Blake2_128Concat, PoolId, PoolOf, OptionQuery>; - // TODO(#1212): Remove in v0.5.1. - #[pallet::storage] - #[pallet::getter(fn pools_cached_for_arbitrage)] - pub type PoolsCachedForArbitrage = StorageMap<_, Twox64Concat, PoolId, ()>; - - // TODO(#1212): Remove in v0.5.1. - #[pallet::storage] - #[pallet::getter(fn subsidy_providers)] - pub type SubsidyProviders = - StorageDoubleMap<_, Twox64Concat, PoolId, Twox64Concat, T::AccountId, BalanceOf>; - #[pallet::storage] #[pallet::getter(fn next_pool_id)] pub(crate) type NextPoolId = StorageValue<_, PoolId, ValueQuery>; diff --git a/zrml/swaps/src/migrations.rs b/zrml/swaps/src/migrations.rs index 88b9fd515..8853c4110 100644 --- a/zrml/swaps/src/migrations.rs +++ b/zrml/swaps/src/migrations.rs @@ -21,388 +21,3 @@ // (, contact@balancer.finance) in the // balancer-core repository // . - -use crate::{ - types::{Pool, PoolStatus}, - BalanceOf, Config, Pallet as Swaps, PoolOf, PoolsCachedForArbitrage, SubsidyProviders, -}; -use alloc::{collections::BTreeMap, vec::Vec}; -use core::marker::PhantomData; -use frame_support::{ - log, - pallet_prelude::{Blake2_128Concat, StorageVersion, Weight}, - traits::{Get, OnRuntimeUpgrade}, -}; -use parity_scale_codec::{Compact, Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::{RuntimeDebug, SaturatedConversion, Saturating}; -use zeitgeist_primitives::{ - constants::MAX_ASSETS, - types::{Asset, MarketId, PoolId, ScoringRule}, -}; - -#[cfg(feature = "try-runtime")] -use frame_support::migration::storage_key_iter; - -#[cfg(any(feature = "try-runtime", test))] -const SWAPS: &[u8] = b"Swaps"; -#[cfg(any(feature = "try-runtime", test))] -const POOLS: &[u8] = b"Pools"; - -#[derive(TypeInfo, Clone, Encode, Eq, Decode, PartialEq, RuntimeDebug)] -pub struct OldPool -where - MarketId: MaxEncodedLen, -{ - pub assets: Vec>, - pub base_asset: Asset, - pub market_id: MarketId, - pub pool_status: OldPoolStatus, - pub scoring_rule: OldScoringRule, - pub swap_fee: Option, - pub total_subsidy: Option, - pub total_weight: Option, - pub weights: Option, u128>>, -} - -impl MaxEncodedLen for OldPool -where - Balance: MaxEncodedLen, - MarketId: MaxEncodedLen, -{ - fn max_encoded_len() -> usize { - let max_encoded_length_bytes = >::max_encoded_len(); - let b_tree_map_size = 1usize - .saturating_add(MAX_ASSETS.saturated_into::().saturating_mul( - >::max_encoded_len().saturating_add(u128::max_encoded_len()), - )) - .saturating_add(max_encoded_length_bytes); - - >::max_encoded_len() - .saturating_mul(MAX_ASSETS.saturated_into::()) - .saturating_add(max_encoded_length_bytes) - .saturating_add(>>::max_encoded_len()) - .saturating_add(MarketId::max_encoded_len()) - .saturating_add(PoolStatus::max_encoded_len()) - .saturating_add(ScoringRule::max_encoded_len()) - .saturating_add(>::max_encoded_len().saturating_mul(2)) - .saturating_add(>::max_encoded_len()) - .saturating_add(b_tree_map_size) - } -} - -#[derive(TypeInfo, Clone, Copy, Encode, Eq, Decode, MaxEncodedLen, PartialEq, RuntimeDebug)] -pub enum OldScoringRule { - CPMM, - RikiddoSigmoidFeeMarketEma, - Lmsr, - Orderbook, - Parimutuel, -} - -#[cfg_attr(feature = "std", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -#[derive( - parity_scale_codec::Decode, - parity_scale_codec::Encode, - parity_scale_codec::MaxEncodedLen, - scale_info::TypeInfo, - Clone, - Copy, - Debug, - Eq, - Ord, - PartialEq, - PartialOrd, -)] -pub enum OldPoolStatus { - Active, - CollectingSubsidy, - Closed, - Clean, - Initialized, -} - -pub(crate) type OldPoolOf = OldPool, MarketId>; - -#[frame_support::storage_alias] -pub(crate) type Pools = - StorageMap, Blake2_128Concat, PoolId, Option>>; - -const SWAPS_REQUIRED_STORAGE_VERSION: u16 = 3; -const SWAPS_NEXT_STORAGE_VERSION: u16 = 4; - -#[frame_support::storage_alias] -pub(crate) type Markets = StorageMap, Blake2_128Concat, PoolId, OldPoolOf>; - -pub struct MigratePools(PhantomData); - -/// Deletes all Rikiddo markets from storage, migrates CPMM markets to their new storage layout and -/// closes them. Due to us abstracting `MarketId` away from the `Asset` type of the `Config` object, -/// we require that the old asset type `Asset` be convertible to the generic `T::Asset`. -/// The migration also clears the `SubsidyProviders` and `PoolsCachedForArbitrage` storage elements. -impl OnRuntimeUpgrade for MigratePools -where - T: Config, - ::Asset: From>, -{ - fn on_runtime_upgrade() -> Weight { - let mut total_weight = T::DbWeight::get().reads(1); - let swaps_version = StorageVersion::get::>(); - if swaps_version != SWAPS_REQUIRED_STORAGE_VERSION { - log::info!( - "MigratePools: swaps version is {:?}, but {:?} is required", - swaps_version, - SWAPS_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("MigratePools: Starting..."); - - let mut reads_writes = 0u64; - crate::Pools::::translate::>, _>(|_, opt_old_pool| { - // We proceed by deleting Rikiddo pools; CPMM pools are migrated to the new version - // _and_ closed (because their respective markets are being switched to LMSR). - reads_writes.saturating_inc(); - let old_pool = opt_old_pool?; - if old_pool.scoring_rule != OldScoringRule::CPMM { - return None; - } - // These conversions should all be infallible. - let assets_unbounded = - old_pool.assets.into_iter().map(Into::into).collect::>(); - let assets = assets_unbounded.try_into().ok()?; - let status = match old_pool.pool_status { - OldPoolStatus::Active => PoolStatus::Closed, - OldPoolStatus::CollectingSubsidy => return None, - OldPoolStatus::Closed => PoolStatus::Closed, - OldPoolStatus::Clean => PoolStatus::Closed, - OldPoolStatus::Initialized => PoolStatus::Closed, - }; - let swap_fee = old_pool.swap_fee?; - let weights_unbounded = old_pool - .weights? - .into_iter() - .map(|(k, v)| (k.into(), v)) - .collect::>(); - let weights = weights_unbounded.try_into().ok()?; - let total_weight = old_pool.total_weight?; - let new_pool: PoolOf = Pool { assets, status, swap_fee, total_weight, weights }; - Some(new_pool) - }); - log::info!("MigratePools: Upgraded {} pools.", reads_writes); - reads_writes = reads_writes.saturating_add(SubsidyProviders::::drain().count() as u64); - reads_writes = - reads_writes.saturating_add(PoolsCachedForArbitrage::::drain().count() as u64); - total_weight = total_weight - .saturating_add(T::DbWeight::get().reads_writes(reads_writes, reads_writes)); - StorageVersion::new(SWAPS_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("MigratePools: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - let old_pools = - storage_key_iter::>, Blake2_128Concat>(SWAPS, POOLS) - .collect::>(); - let pools = Pools::::iter_keys().count(); - let decodable_pools = Pools::::iter_values().count(); - if pools == decodable_pools { - log::info!("All {} pools could successfully be decoded.", pools); - } else { - log::error!( - "Can only decode {} of {} pools - others will be dropped.", - decodable_pools, - pools - ); - } - Ok(old_pools.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { - let old_pools: BTreeMap>> = - Decode::decode(&mut &previous_state[..]).unwrap(); - let old_pool_count = old_pools.len(); - let new_pool_count = crate::Pools::::iter().count(); - assert_eq!(old_pool_count, new_pool_count); - log::info!("MigratePools: Pool counter post-upgrade is {}!", new_pool_count); - if PoolsCachedForArbitrage::::iter().count() != 0 { - return Err("MigratePools: PoolsCachedForArbitrage is not empty!"); - } - if SubsidyProviders::::iter().count() != 0 { - return Err("MigratePools: SubsidyProviders is not empty!"); - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{ExtBuilder, Runtime}; - use alloc::fmt::Debug; - use frame_support::{migration::put_storage_value, storage_root, StorageHasher}; - use sp_runtime::StateVersion; - use test_case::test_case; - use zeitgeist_macros::create_b_tree_map; - use zeitgeist_primitives::types::Asset; - - #[test] - fn on_runtime_upgrade_increments_the_storage_version() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - MigratePools::::on_runtime_upgrade(); - assert_eq!(StorageVersion::get::>(), SWAPS_NEXT_STORAGE_VERSION); - }); - } - - #[test] - fn on_runtime_upgrade_clears_storage_correctly() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - PoolsCachedForArbitrage::::insert(4, ()); - SubsidyProviders::::insert(1, 2, 3); - MigratePools::::on_runtime_upgrade(); - assert_eq!(PoolsCachedForArbitrage::::iter().count(), 0); - assert_eq!(SubsidyProviders::::iter().count(), 0); - }); - } - - #[test_case(OldPoolStatus::Active)] - #[test_case(OldPoolStatus::Closed)] - #[test_case(OldPoolStatus::Clean)] - #[test_case(OldPoolStatus::Initialized)] - fn on_runtime_upgrade_works_as_expected_with_cpmm(old_pool_status: OldPoolStatus) { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let base_asset = Asset::ForeignAsset(4); - let market_id = 1; - let assets = vec![ - Asset::CategoricalOutcome(market_id, 0), - Asset::CategoricalOutcome(market_id, 1), - Asset::CategoricalOutcome(market_id, 2), - base_asset, - ]; - let swap_fee = 5; - let total_weight = 8; - let weights = create_b_tree_map!({ - Asset::CategoricalOutcome(market_id, 0) => 1, - Asset::CategoricalOutcome(market_id, 1) => 2, - Asset::CategoricalOutcome(market_id, 2) => 1, - base_asset => 8, - }); - let opt_old_pool = Some(OldPool { - assets: assets.clone(), - base_asset, - market_id, - pool_status: old_pool_status, - scoring_rule: OldScoringRule::CPMM, - swap_fee: Some(swap_fee), - total_subsidy: None, - total_weight: Some(total_weight), - weights: Some(weights.clone()), - }); - populate_test_data::>>( - SWAPS, - POOLS, - vec![opt_old_pool], - ); - MigratePools::::on_runtime_upgrade(); - let actual = crate::Pools::::get(0); - let expected = Some(Pool { - assets: assets.try_into().unwrap(), - status: PoolStatus::Closed, - swap_fee, - total_weight, - weights: weights.try_into().unwrap(), - }); - assert_eq!(actual, expected); - }); - } - - #[test_case(OldPoolStatus::Active)] - #[test_case(OldPoolStatus::CollectingSubsidy)] - #[test_case(OldPoolStatus::Closed)] - #[test_case(OldPoolStatus::Clean)] - #[test_case(OldPoolStatus::Initialized)] - fn on_runtime_upgrade_works_as_expected_with_rikiddo(pool_status: OldPoolStatus) { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let base_asset = Asset::ForeignAsset(4); - let market_id = 1; - let assets = vec![ - Asset::CategoricalOutcome(market_id, 0), - Asset::CategoricalOutcome(market_id, 1), - Asset::CategoricalOutcome(market_id, 2), - base_asset, - ]; - let opt_old_pool = Some(OldPool { - assets: assets.clone(), - base_asset, - market_id, - pool_status, - scoring_rule: OldScoringRule::RikiddoSigmoidFeeMarketEma, - swap_fee: Some(5), - total_subsidy: Some(123), - total_weight: None, - weights: None, - }); - populate_test_data::>>( - SWAPS, - POOLS, - vec![opt_old_pool], - ); - MigratePools::::on_runtime_upgrade(); - let actual = crate::Pools::::get(0); - assert_eq!(actual, None); - }); - } - - #[test] - fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - StorageVersion::new(SWAPS_NEXT_STORAGE_VERSION).put::>(); - let assets = - vec![Asset::ForeignAsset(0), Asset::ForeignAsset(1), Asset::ForeignAsset(2)]; - let weights = create_b_tree_map!({ - Asset::ForeignAsset(0) => 3, - Asset::ForeignAsset(1) => 4, - Asset::ForeignAsset(2) => 5, - }); - let pool = Pool { - assets: assets.try_into().unwrap(), - status: PoolStatus::Open, - swap_fee: 4, - total_weight: 12, - weights: weights.try_into().unwrap(), - }; - crate::Pools::::insert(0, pool); - PoolsCachedForArbitrage::::insert(4, ()); - SubsidyProviders::::insert(1, 2, 3); - let tmp = storage_root(StateVersion::V1); - MigratePools::::on_runtime_upgrade(); - assert_eq!(tmp, storage_root(StateVersion::V1)); - }); - } - - fn set_up_version() { - StorageVersion::new(SWAPS_REQUIRED_STORAGE_VERSION).put::>(); - } - - #[allow(unused)] - fn populate_test_data(pallet: &[u8], prefix: &[u8], data: Vec) - where - H: StorageHasher, - K: TryFrom + Encode, - V: Encode + Clone, - >::Error: Debug, - { - for (key, value) in data.iter().enumerate() { - let storage_hash = K::try_from(key).unwrap().using_encoded(H::hash).as_ref().to_vec(); - put_storage_value::(pallet, prefix, &storage_hash, (*value).clone()); - } - } -}