diff --git a/primitives/src/market.rs b/primitives/src/market.rs index c590c0d54..edd51c71e 100644 --- a/primitives/src/market.rs +++ b/primitives/src/market.rs @@ -61,7 +61,7 @@ pub struct Market { /// The resolved outcome. pub resolved_outcome: Option, /// See [`MarketDisputeMechanism`]. - pub dispute_mechanism: MarketDisputeMechanism, + pub dispute_mechanism: Option, /// The bonds reserved for this market. pub bonds: MarketBonds, } @@ -162,7 +162,7 @@ where .saturating_add(MarketStatus::max_encoded_len()) .saturating_add(>>::max_encoded_len()) .saturating_add(>::max_encoded_len()) - .saturating_add(::max_encoded_len()) + .saturating_add(>::max_encoded_len()) .saturating_add(>::max_encoded_len()) } } @@ -393,7 +393,7 @@ mod tests { status: MarketStatus::Active, report: None, resolved_outcome: None, - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), bonds: MarketBonds::default(), }; assert_eq!(market.matches_outcome_report(&outcome_report), expected); diff --git a/runtime/battery-station/src/lib.rs b/runtime/battery-station/src/lib.rs index 8e26a9494..5e251eada 100644 --- a/runtime/battery-station/src/lib.rs +++ b/runtime/battery-station/src/lib.rs @@ -128,16 +128,16 @@ impl Contains for ContractsCallfilter { dispute { .. } => true, // Only allow CPMM markets using Authorized or SimpleDisputes dispute mechanism create_market { - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), scoring_rule: ScoringRule::CPMM, .. } => true, create_cpmm_market_and_deploy_assets { - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), .. } => true, edit_market { - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), scoring_rule: ScoringRule::CPMM, .. } => true, @@ -180,18 +180,18 @@ impl Contains for IsCallable { scoring_rule: ScoringRule::RikiddoSigmoidFeeMarketEma, .. } => false, create_market { - dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), .. } => false, edit_market { scoring_rule: ScoringRule::RikiddoSigmoidFeeMarketEma, .. } => false, create_cpmm_market_and_deploy_assets { - dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), .. } => false, edit_market { - dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), .. } => false, _ => true, diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index bc33c2c17..bbace19cb 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -45,35 +45,23 @@ pub mod weights; #[macro_export] macro_rules! decl_common_types { - {} => { - use sp_runtime::generic; + () => { + use frame_support::traits::{ + Currency, Imbalance, NeverEnsureOrigin, OnRuntimeUpgrade, OnUnbalanced, + }; #[cfg(feature = "try-runtime")] - use frame_try_runtime::{UpgradeCheckSelect, TryStateSelect}; - use frame_support::traits::{Currency, Imbalance, OnRuntimeUpgrade, OnUnbalanced, NeverEnsureOrigin}; + use frame_try_runtime::{TryStateSelect, UpgradeCheckSelect}; + use sp_runtime::generic; pub type Block = generic::Block; type Address = sp_runtime::MultiAddress; #[cfg(feature = "parachain")] - type Migrations = ( - orml_asset_registry::Migration, - orml_unknown_tokens::Migration, - pallet_xcm::migration::v1::MigrateToV1, - // IMPORTANT that AddDisputeBondAndConvertCreatorFee comes before MoveDataToSimpleDisputes!!! - zrml_prediction_markets::migrations::AddDisputeBondAndConvertCreatorFee, - zrml_prediction_markets::migrations::MoveDataToSimpleDisputes, - zrml_global_disputes::migrations::ModifyGlobalDisputesStructures, - ); + type Migrations = (zrml_prediction_markets::migrations::MigrateMarkets,); #[cfg(not(feature = "parachain"))] - type Migrations = ( - pallet_grandpa::migrations::CleanupSetIdSessionMap, - // IMPORTANT that AddDisputeBondAndConvertCreatorFee comes before MoveDataToSimpleDisputes!!! - zrml_prediction_markets::migrations::AddDisputeBondAndConvertCreatorFee, - zrml_prediction_markets::migrations::MoveDataToSimpleDisputes, - zrml_global_disputes::migrations::ModifyGlobalDisputesStructures, - ); + type Migrations = (zrml_prediction_markets::migrations::MigrateMarkets,); pub type Executive = frame_executive::Executive< Runtime, @@ -99,7 +87,8 @@ macro_rules! decl_common_types { pallet_asset_tx_payment::ChargeAssetTxPayment, ); pub type SignedPayload = generic::SignedPayload; - pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; // Governance type AdvisoryCommitteeInstance = pallet_collective::Instance1; @@ -111,20 +100,28 @@ macro_rules! decl_common_types { // Council vote proportions // At least 50% - type EnsureRootOrHalfCouncil = - EitherOfDiverse, EnsureProportionAtLeast>; + type EnsureRootOrHalfCouncil = EitherOfDiverse< + EnsureRoot, + EnsureProportionAtLeast, + >; // At least 66% - type EnsureRootOrTwoThirdsCouncil = - EitherOfDiverse, EnsureProportionAtLeast>; + type EnsureRootOrTwoThirdsCouncil = EitherOfDiverse< + EnsureRoot, + EnsureProportionAtLeast, + >; // At least 75% - type EnsureRootOrThreeFourthsCouncil = - EitherOfDiverse, EnsureProportionAtLeast>; + type EnsureRootOrThreeFourthsCouncil = EitherOfDiverse< + EnsureRoot, + EnsureProportionAtLeast, + >; // At least 100% - type EnsureRootOrAllCouncil = - EitherOfDiverse, EnsureProportionAtLeast>; + type EnsureRootOrAllCouncil = EitherOfDiverse< + EnsureRoot, + EnsureProportionAtLeast, + >; // Technical committee vote proportions // At least 50% @@ -248,7 +245,7 @@ macro_rules! decl_common_types { } } } - } + }; } // Construct runtime diff --git a/runtime/zeitgeist/src/lib.rs b/runtime/zeitgeist/src/lib.rs index 44811a014..25b6918cb 100644 --- a/runtime/zeitgeist/src/lib.rs +++ b/runtime/zeitgeist/src/lib.rs @@ -174,10 +174,10 @@ impl Contains for IsCallable { create_market { scoring_rule: RikiddoSigmoidFeeMarketEma, .. } => false, edit_market { scoring_rule: RikiddoSigmoidFeeMarketEma, .. } => false, // Disable Court & SimpleDisputes dispute resolution mechanism - create_market { dispute_mechanism: Court | SimpleDisputes, .. } => false, - edit_market { dispute_mechanism: Court | SimpleDisputes, .. } => false, + create_market { dispute_mechanism: Some(Court | SimpleDisputes), .. } => false, + edit_market { dispute_mechanism: Some(Court | SimpleDisputes), .. } => false, create_cpmm_market_and_deploy_assets { - dispute_mechanism: Court | SimpleDisputes, + dispute_mechanism: Some(Court | SimpleDisputes), .. } => false, _ => true, diff --git a/zrml/authorized/src/lib.rs b/zrml/authorized/src/lib.rs index b5b13b02e..c26cb7a33 100644 --- a/zrml/authorized/src/lib.rs +++ b/zrml/authorized/src/lib.rs @@ -45,7 +45,7 @@ mod pallet { PalletId, Twox64Concat, }; use frame_system::pallet_prelude::OriginFor; - use sp_runtime::{traits::Saturating, DispatchError}; + use sp_runtime::{traits::Saturating, DispatchError, DispatchResult}; use zeitgeist_primitives::{ traits::{DisputeApi, DisputeMaxWeightApi, DisputeResolutionApi}, types::{ @@ -95,10 +95,7 @@ mod pallet { let market = T::MarketCommons::market(&market_id)?; ensure!(market.status == MarketStatus::Disputed, Error::::MarketIsNotDisputed); ensure!(market.matches_outcome_report(&outcome), Error::::OutcomeMismatch); - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(&market)?; let now = frame_system::Pallet::::block_number(); @@ -192,6 +189,15 @@ mod pallet { fn get_auto_resolve(market_id: &MarketIdOf) -> Option { AuthorizedOutcomeReports::::get(market_id).map(|report| report.resolve_at) } + + #[inline] + fn ensure_dispute_mechanism(market: &MarketOf) -> DispatchResult { + ensure!( + market.dispute_mechanism == Some(MarketDisputeMechanism::Authorized), + Error::::MarketDoesNotHaveDisputeMechanismAuthorized + ); + Ok(()) + } } impl DisputeMaxWeightApi for Pallet @@ -243,10 +249,7 @@ mod pallet { _: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(market)?; let res = ResultWithWeightInfo { result: (), weight: T::WeightInfo::on_dispute_weight() }; @@ -258,10 +261,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result>, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(market)?; let report = AuthorizedOutcomeReports::::take(market_id); let res = ResultWithWeightInfo { @@ -278,10 +278,7 @@ mod pallet { _: &OutcomeReport, overall_imbalance: NegativeImbalanceOf, ) -> Result>, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(market)?; // all funds to treasury let res = ResultWithWeightInfo { result: overall_imbalance, @@ -300,7 +297,7 @@ mod pallet { weight: T::WeightInfo::get_auto_resolve_weight(), }; - if market.dispute_mechanism != MarketDisputeMechanism::Authorized { + if market.dispute_mechanism != Some(MarketDisputeMechanism::Authorized) { return res; } @@ -313,10 +310,7 @@ mod pallet { _: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(market)?; let res = ResultWithWeightInfo { result: false, weight: T::WeightInfo::has_failed_weight() }; @@ -331,10 +325,7 @@ mod pallet { ResultWithWeightInfo>>, DispatchError, > { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(market)?; let res = ResultWithWeightInfo { result: Vec::new(), @@ -348,10 +339,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Authorized, - Error::::MarketDoesNotHaveDisputeMechanismAuthorized - ); + Self::ensure_dispute_mechanism(market)?; AuthorizedOutcomeReports::::remove(market_id); @@ -385,7 +373,7 @@ where creator_fee: sp_runtime::Perbill::zero(), creator: T::PalletId::get().into_account_truncating(), market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=100), - dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), metadata: Default::default(), oracle: T::PalletId::get().into_account_truncating(), period: zeitgeist_primitives::types::MarketPeriod::Block(Default::default()), diff --git a/zrml/authorized/src/tests.rs b/zrml/authorized/src/tests.rs index 018db50eb..81192a638 100644 --- a/zrml/authorized/src/tests.rs +++ b/zrml/authorized/src/tests.rs @@ -101,7 +101,7 @@ fn authorize_market_outcome_fails_if_market_does_not_exist() { fn authorize_market_outcome_fails_on_non_authorized_market() { ExtBuilder::default().build().execute_with(|| { let mut market = market_mock::(); - market.dispute_mechanism = MarketDisputeMechanism::Court; + market.dispute_mechanism = Some(MarketDisputeMechanism::Court); Markets::::insert(0, market); assert_noop!( Authorized::authorize_market_outcome( diff --git a/zrml/court/src/benchmarks.rs b/zrml/court/src/benchmarks.rs index fdc20aae2..97729349a 100644 --- a/zrml/court/src/benchmarks.rs +++ b/zrml/court/src/benchmarks.rs @@ -59,7 +59,7 @@ where creator_fee: sp_runtime::Perbill::zero(), creator: account("creator", 0, 0), market_type: MarketType::Scalar(0..=100), - dispute_mechanism: MarketDisputeMechanism::Court, + dispute_mechanism: Some(MarketDisputeMechanism::Court), metadata: vec![], oracle: account("oracle", 0, 0), period: MarketPeriod::Block( diff --git a/zrml/court/src/lib.rs b/zrml/court/src/lib.rs index 0a19a1576..5ea958bc6 100644 --- a/zrml/court/src/lib.rs +++ b/zrml/court/src/lib.rs @@ -1774,10 +1774,7 @@ mod pallet { if let Some(market_id) = >::get(court_id) { let market = T::MarketCommons::market(&market_id)?; ensure!(market.status == MarketStatus::Disputed, Error::::MarketIsNotDisputed); - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(&market)?; } ensure!( @@ -1806,6 +1803,15 @@ mod pallet { T::TreasuryPalletId::get().into_account_truncating() } + #[inline] + fn ensure_dispute_mechanism(market: &MarketOf) -> DispatchResult { + ensure!( + market.dispute_mechanism == Some(MarketDisputeMechanism::Court), + Error::::MarketDoesNotHaveCourtMechanism + ); + Ok(()) + } + /// The court has a specific vote item type. /// We ensure that the vote item matches the predefined vote item type. pub(crate) fn check_vote_item( @@ -2112,10 +2118,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(market)?; let court_id = >::get(); let next_court_id = @@ -2160,10 +2163,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result>, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(market)?; let court_id = >::get(market_id) .ok_or(Error::::MarketIdToCourtIdNotFound)?; @@ -2192,10 +2192,7 @@ mod pallet { resolved_outcome: &OutcomeReport, mut overall_imbalance: NegativeImbalanceOf, ) -> Result>, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(market)?; let court_id = >::get(market_id) .ok_or(Error::::MarketIdToCourtIdNotFound)?; @@ -2231,7 +2228,7 @@ mod pallet { let mut res = ResultWithWeightInfo { result: None, weight: T::WeightInfo::get_auto_resolve() }; - if market.dispute_mechanism != MarketDisputeMechanism::Court { + if market.dispute_mechanism != Some(MarketDisputeMechanism::Court) { return res; } @@ -2246,10 +2243,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(market)?; let mut has_failed = false; let now = >::block_number(); @@ -2314,10 +2308,7 @@ mod pallet { ResultWithWeightInfo>>, DispatchError, > { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(market)?; // oracle outcome is added by pm-pallet let mut gd_outcomes: Vec> = @@ -2376,10 +2367,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::Court, - Error::::MarketDoesNotHaveCourtMechanism - ); + Self::ensure_dispute_mechanism(market)?; let court_id = >::get(market_id) .ok_or(Error::::MarketIdToCourtIdNotFound)?; diff --git a/zrml/court/src/tests.rs b/zrml/court/src/tests.rs index 72fd7a378..880649471 100644 --- a/zrml/court/src/tests.rs +++ b/zrml/court/src/tests.rs @@ -67,7 +67,7 @@ const DEFAULT_MARKET: MarketOf = Market { creator_fee: sp_runtime::Perbill::zero(), creator: 0, market_type: MarketType::Scalar(0..=100), - dispute_mechanism: MarketDisputeMechanism::Court, + dispute_mechanism: Some(MarketDisputeMechanism::Court), metadata: vec![], oracle: 0, period: MarketPeriod::Block(0..100), @@ -1692,7 +1692,7 @@ fn check_appealable_market_fails_if_dispute_mechanism_wrong() { let market_id = >::get(court_id).unwrap(); MarketCommons::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::SimpleDisputes; + market.dispute_mechanism = Some(MarketDisputeMechanism::SimpleDisputes); Ok(()) }) .unwrap(); @@ -2402,7 +2402,7 @@ fn reassign_court_stakes_rewards_treasury_if_no_winner() { fn on_dispute_denies_non_court_markets() { ExtBuilder::default().build().execute_with(|| { let mut market = DEFAULT_MARKET; - market.dispute_mechanism = MarketDisputeMechanism::SimpleDisputes; + market.dispute_mechanism = Some(MarketDisputeMechanism::SimpleDisputes); assert_noop!( Court::on_dispute(&0, &market), Error::::MarketDoesNotHaveCourtMechanism @@ -2439,7 +2439,7 @@ fn on_resolution_fails_if_court_not_found() { fn on_resolution_denies_non_court_markets() { ExtBuilder::default().build().execute_with(|| { let mut market = DEFAULT_MARKET; - market.dispute_mechanism = MarketDisputeMechanism::SimpleDisputes; + market.dispute_mechanism = Some(MarketDisputeMechanism::SimpleDisputes); assert_noop!( Court::on_resolution(&0, &market), Error::::MarketDoesNotHaveCourtMechanism @@ -2451,7 +2451,7 @@ fn on_resolution_denies_non_court_markets() { fn exchange_fails_if_non_court_markets() { ExtBuilder::default().build().execute_with(|| { let mut market = DEFAULT_MARKET; - market.dispute_mechanism = MarketDisputeMechanism::SimpleDisputes; + market.dispute_mechanism = Some(MarketDisputeMechanism::SimpleDisputes); assert_noop!( Court::exchange(&0, &market, &ORACLE_REPORT, NegativeImbalance::::zero()), Error::::MarketDoesNotHaveCourtMechanism @@ -2562,7 +2562,7 @@ fn on_global_dispute_removes_draws() { fn on_global_dispute_fails_if_wrong_dispute_mechanism() { ExtBuilder::default().build().execute_with(|| { let mut market = DEFAULT_MARKET; - market.dispute_mechanism = MarketDisputeMechanism::SimpleDisputes; + market.dispute_mechanism = Some(MarketDisputeMechanism::SimpleDisputes); assert_noop!( Court::on_global_dispute(&0, &market), Error::::MarketDoesNotHaveCourtMechanism diff --git a/zrml/global-disputes/src/migrations.rs b/zrml/global-disputes/src/migrations.rs index 597b46789..3bc5ddb7c 100644 --- a/zrml/global-disputes/src/migrations.rs +++ b/zrml/global-disputes/src/migrations.rs @@ -15,369 +15,3 @@ // // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . - -extern crate alloc; - -use crate::{types::*, Config, Pallet as GDPallet, *}; -#[cfg(feature = "try-runtime")] -use alloc::vec::Vec; -use frame_support::{ - dispatch::Weight, - log, - pallet_prelude::PhantomData, - traits::{Get, OnRuntimeUpgrade, StorageVersion}, -}; -use sp_runtime::traits::Saturating; - -#[cfg(feature = "try-runtime")] -use alloc::collections::BTreeMap; -#[cfg(feature = "try-runtime")] -use parity_scale_codec::{Decode, Encode}; -#[cfg(feature = "try-runtime")] -use scale_info::prelude::format; - -const GD_REQUIRED_STORAGE_VERSION: u16 = 0; -const GD_NEXT_STORAGE_VERSION: u16 = 1; - -pub struct ModifyGlobalDisputesStructures(PhantomData); - -impl OnRuntimeUpgrade - for ModifyGlobalDisputesStructures -{ - fn on_runtime_upgrade() -> Weight - where - T: Config, - { - let mut total_weight = T::DbWeight::get().reads(1); - let gd_version = StorageVersion::get::>(); - if gd_version != GD_REQUIRED_STORAGE_VERSION { - log::info!( - "ModifyGlobalDisputesStructures: global disputes version is {:?}, require {:?};", - gd_version, - GD_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("ModifyGlobalDisputesStructures: Starting..."); - - for (market_id, winner_info) in crate::Winners::::drain() { - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - - let owners = winner_info.outcome_info.owners; - let owners_len = owners.len(); - let possession = match owners_len { - 1usize => Possession::Paid { - owner: owners - .get(0) - .expect("Owners len is 1, but could not get this owner.") - .clone(), - fee: T::VotingOutcomeFee::get(), - }, - _ => Possession::Shared { owners }, - }; - - let outcome_info = - OutcomeInfo { outcome_sum: winner_info.outcome_info.outcome_sum, possession }; - let gd_info = GlobalDisputeInfo { - winner_outcome: winner_info.outcome, - outcome_info, - status: GdStatus::Finished, - }; - crate::GlobalDisputesInfo::::insert(market_id, gd_info); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - } - - let mut translated = 0u64; - Outcomes::::translate::, OwnerInfoOf>, _>( - |_key1, _key2, old_value| { - translated.saturating_inc(); - - let owners = old_value.owners; - let owners_len = owners.len(); - let possession = match owners_len { - 1usize => Possession::Paid { - owner: owners - .get(0) - .expect("Owners len is 1, but could not get this owner.") - .clone(), - fee: T::VotingOutcomeFee::get(), - }, - _ => Possession::Shared { owners }, - }; - - let new_value = OutcomeInfo { outcome_sum: old_value.outcome_sum, possession }; - - Some(new_value) - }, - ); - log::info!("ModifyGlobalDisputesStructures: Upgraded {} outcomes.", translated); - total_weight = total_weight - .saturating_add(T::DbWeight::get().reads_writes(translated + 1, translated + 1)); - - StorageVersion::new(GD_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("ModifyGlobalDisputesStructures: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - let old_winners = crate::Winners::::iter() - .collect::, OldWinnerInfo, OwnerInfoOf>>>(); - Ok(old_winners.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { - let mut markets_count = 0_u32; - let old_winners: BTreeMap, OldWinnerInfo, OwnerInfoOf>> = - Decode::decode(&mut &previous_state[..]) - .expect("Failed to decode state: Invalid state"); - for (market_id, gd_info) in crate::GlobalDisputesInfo::::iter() { - let GlobalDisputeInfo { winner_outcome, outcome_info, status } = gd_info; - - let winner_info: &OldWinnerInfo, OwnerInfoOf> = old_winners - .get(&market_id) - .expect(&format!("Market {:?} not found", market_id)[..]); - - assert_eq!(winner_outcome, winner_info.outcome); - assert_eq!(status, GdStatus::Finished); - - let owners = winner_info.outcome_info.owners.clone(); - let owners_len = owners.len(); - - let possession = match owners_len { - 1usize => Possession::Paid { - owner: owners - .get(0) - .expect("Owners len is 1, but could not get this owner.") - .clone(), - fee: T::VotingOutcomeFee::get(), - }, - _ => Possession::Shared { owners }, - }; - - let outcome_info_expected = - OutcomeInfo { outcome_sum: winner_info.outcome_info.outcome_sum, possession }; - assert_eq!(outcome_info, outcome_info_expected); - - markets_count += 1_u32; - } - let old_markets_count = old_winners.len() as u32; - assert_eq!(markets_count, old_markets_count); - - // empty Winners storage map - assert!(crate::Winners::::iter().next().is_none()); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{ExtBuilder, Runtime, ALICE, BOB}; - use frame_support::{ - migration::{get_storage_value, put_storage_value}, - BoundedVec, - }; - use sp_runtime::traits::SaturatedConversion; - use zeitgeist_primitives::{ - constants::mock::VotingOutcomeFee, - types::{MarketId, OutcomeReport}, - }; - - const GLOBAL_DISPUTES: &[u8] = b"GlobalDisputes"; - const GD_OUTCOMES: &[u8] = b"Outcomes"; - - type OldOutcomeInfoOf = OldOutcomeInfo, OwnerInfoOf>; - - #[test] - fn on_runtime_upgrade_increments_the_storage_versions() { - ExtBuilder::default().build().execute_with(|| { - set_up_chain(); - ModifyGlobalDisputesStructures::::on_runtime_upgrade(); - let gd_version = StorageVersion::get::>(); - assert_eq!(gd_version, GD_NEXT_STORAGE_VERSION); - }); - } - - #[test] - fn on_runtime_sets_new_global_disputes_storage_paid() { - ExtBuilder::default().build().execute_with(|| { - set_up_chain(); - - let market_id = 0u128; - - let outcome_sum = 42u128.saturated_into::>(); - let owners = BoundedVec::try_from(vec![ALICE]).unwrap(); - - let outcome_info = OldOutcomeInfo { outcome_sum, owners }; - let outcome = OutcomeReport::Categorical(42u16); - let winner_info = - OldWinnerInfo { outcome: outcome.clone(), outcome_info, is_finished: true }; - - crate::Winners::::insert(market_id, winner_info); - - ModifyGlobalDisputesStructures::::on_runtime_upgrade(); - - let possession = Possession::Paid { owner: ALICE, fee: VotingOutcomeFee::get() }; - - let new_outcome_info = OutcomeInfo { outcome_sum, possession }; - - let expected = GlobalDisputeInfo { - winner_outcome: outcome, - outcome_info: new_outcome_info, - status: GdStatus::Finished, - }; - - let actual = crate::GlobalDisputesInfo::::get(market_id).unwrap(); - assert_eq!(expected, actual); - - assert!(crate::Winners::::iter().next().is_none()); - }); - } - - #[test] - fn on_runtime_sets_new_global_disputes_storage_shared() { - ExtBuilder::default().build().execute_with(|| { - set_up_chain(); - - let market_id = 0u128; - - let outcome_sum = 42u128.saturated_into::>(); - let owners = BoundedVec::try_from(vec![ALICE, BOB]).unwrap(); - - let outcome_info = OldOutcomeInfo { outcome_sum, owners: owners.clone() }; - let outcome = OutcomeReport::Categorical(42u16); - let winner_info = - OldWinnerInfo { outcome: outcome.clone(), outcome_info, is_finished: true }; - - crate::Winners::::insert(market_id, winner_info); - - ModifyGlobalDisputesStructures::::on_runtime_upgrade(); - - let possession = Possession::Shared { owners }; - - let new_outcome_info = OutcomeInfo { outcome_sum, possession }; - - let expected = GlobalDisputeInfo { - winner_outcome: outcome, - outcome_info: new_outcome_info, - status: GdStatus::Finished, - }; - - let actual = crate::GlobalDisputesInfo::::get(market_id).unwrap(); - assert_eq!(expected, actual); - - assert!(crate::Winners::::iter().next().is_none()); - }); - } - - #[test] - fn on_runtime_sets_new_outcomes_storage_value_shared() { - ExtBuilder::default().build().execute_with(|| { - set_up_chain(); - - let outcome = OutcomeReport::Categorical(0u16); - let hash = - crate::Outcomes::::hashed_key_for::(0, outcome); - - let outcome_sum = 42u128.saturated_into::>(); - let owners = BoundedVec::try_from(vec![ALICE, BOB]).unwrap(); - - let outcome_info = OldOutcomeInfo { outcome_sum, owners: owners.clone() }; - - put_storage_value::>( - GLOBAL_DISPUTES, - GD_OUTCOMES, - &hash, - outcome_info, - ); - - ModifyGlobalDisputesStructures::::on_runtime_upgrade(); - - let possession = Possession::Shared { owners }; - let expected = OutcomeInfo { outcome_sum, possession }; - - let actual = frame_support::migration::get_storage_value::>( - GLOBAL_DISPUTES, - GD_OUTCOMES, - &hash, - ) - .unwrap(); - assert_eq!(expected, actual); - }); - } - - #[test] - fn on_runtime_sets_new_outcomes_storage_value_paid() { - ExtBuilder::default().build().execute_with(|| { - set_up_chain(); - - let outcome = OutcomeReport::Categorical(0u16); - let hash = - crate::Outcomes::::hashed_key_for::(0, outcome); - - let outcome_sum = 42u128.saturated_into::>(); - let owners = BoundedVec::try_from(vec![ALICE]).unwrap(); - - let outcome_info = OldOutcomeInfo { outcome_sum, owners }; - - put_storage_value::>( - GLOBAL_DISPUTES, - GD_OUTCOMES, - &hash, - outcome_info, - ); - - ModifyGlobalDisputesStructures::::on_runtime_upgrade(); - - let possession = Possession::Paid { owner: ALICE, fee: VotingOutcomeFee::get() }; - let expected = OutcomeInfo { outcome_sum, possession }; - - let actual = frame_support::migration::get_storage_value::>( - GLOBAL_DISPUTES, - GD_OUTCOMES, - &hash, - ) - .unwrap(); - assert_eq!(expected, actual); - }); - } - - #[test] - fn on_runtime_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - // storage migration already executed (storage version is incremented already) - StorageVersion::new(GD_NEXT_STORAGE_VERSION).put::>(); - - let outcome = OutcomeReport::Categorical(0u16); - let hash = - crate::Outcomes::::hashed_key_for::(0, outcome); - - let outcome_info = OldOutcomeInfo { - outcome_sum: 0u128.saturated_into::>(), - owners: BoundedVec::try_from(vec![ALICE]).unwrap(), - }; - - put_storage_value::>( - GLOBAL_DISPUTES, - GD_OUTCOMES, - &hash, - outcome_info, - ); - - ModifyGlobalDisputesStructures::::on_runtime_upgrade(); - - // no changes should have been made, because the storage version was already incremented - assert!( - get_storage_value::>(GLOBAL_DISPUTES, GD_OUTCOMES, &hash) - .is_none() - ); - }); - } - - fn set_up_chain() { - StorageVersion::new(GD_REQUIRED_STORAGE_VERSION).put::>(); - } -} diff --git a/zrml/global-disputes/src/utils.rs b/zrml/global-disputes/src/utils.rs index 866bb06e5..bd87378bf 100644 --- a/zrml/global-disputes/src/utils.rs +++ b/zrml/global-disputes/src/utils.rs @@ -45,7 +45,9 @@ where creator_fee: sp_runtime::Perbill::zero(), creator: T::GlobalDisputesPalletId::get().into_account_truncating(), market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=u128::MAX), - dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some( + zeitgeist_primitives::types::MarketDisputeMechanism::SimpleDisputes, + ), metadata: Default::default(), oracle: T::GlobalDisputesPalletId::get().into_account_truncating(), period: zeitgeist_primitives::types::MarketPeriod::Block(Default::default()), diff --git a/zrml/liquidity-mining/src/tests.rs b/zrml/liquidity-mining/src/tests.rs index 380ed39dc..88c0f7c98 100644 --- a/zrml/liquidity-mining/src/tests.rs +++ b/zrml/liquidity-mining/src/tests.rs @@ -208,7 +208,7 @@ fn create_default_market(market_id: u128, period: Range) { creator_fee: sp_runtime::Perbill::zero(), creator: 0, market_type: MarketType::Categorical(0), - dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), metadata: vec![], oracle: 0, period: MarketPeriod::Block(period), diff --git a/zrml/market-commons/src/tests.rs b/zrml/market-commons/src/tests.rs index a65462392..025091e19 100644 --- a/zrml/market-commons/src/tests.rs +++ b/zrml/market-commons/src/tests.rs @@ -39,7 +39,7 @@ const MARKET_DUMMY: Market MarketCreation { } #[inline] -fn market_dispute_mechanism(seed: u8) -> MarketDisputeMechanism { - match seed % 3 { - 0 => MarketDisputeMechanism::Authorized, - 1 => MarketDisputeMechanism::Court, - _ => MarketDisputeMechanism::SimpleDisputes, +fn market_dispute_mechanism(seed: u8) -> Option { + match seed % 4 { + 0 => Some(MarketDisputeMechanism::Authorized), + 1 => Some(MarketDisputeMechanism::Court), + 2 => Some(MarketDisputeMechanism::SimpleDisputes), + _ => None, } } diff --git a/zrml/prediction-markets/src/benchmarks.rs b/zrml/prediction-markets/src/benchmarks.rs index dea996ae6..777bff022 100644 --- a/zrml/prediction-markets/src/benchmarks.rs +++ b/zrml/prediction-markets/src/benchmarks.rs @@ -61,12 +61,8 @@ const LIQUIDITY: u128 = 100 * BASE; // Get default values for market creation. Also spawns an account with maximum // amount of native currency -fn create_market_common_parameters( - permission: MarketCreation, -) -> Result< - (T::AccountId, T::AccountId, Deadlines, MultiHash, MarketCreation), - &'static str, -> { +fn create_market_common_parameters() +-> Result<(T::AccountId, T::AccountId, Deadlines, MultiHash), &'static str> { let caller: T::AccountId = whitelisted_caller(); T::AssetManager::deposit(Asset::Ztg, &caller, (100u128 * LIQUIDITY).saturated_into()).unwrap(); let oracle = caller.clone(); @@ -78,13 +74,12 @@ fn create_market_common_parameters( let mut metadata = [0u8; 50]; metadata[0] = 0x15; metadata[1] = 0x30; - let creation = permission; - Ok((caller, oracle, deadlines, MultiHash::Sha3_384(metadata), creation)) + Ok((caller, oracle, deadlines, MultiHash::Sha3_384(metadata))) } // Create a market based on common parameters fn create_market_common( - permission: MarketCreation, + creation: MarketCreation, options: MarketType, scoring_rule: ScoringRule, period: Option>>, @@ -94,8 +89,7 @@ fn create_market_common( let range_end: MomentOf = 1_000_000u64.saturated_into(); let creator_fee: Perbill = Perbill::zero(); let period = period.unwrap_or(MarketPeriod::Timestamp(range_start..range_end)); - let (caller, oracle, deadlines, metadata, creation) = - create_market_common_parameters::(permission)?; + let (caller, oracle, deadlines, metadata) = create_market_common_parameters::()?; Call::::create_market { base_asset: Asset::Ztg, creator_fee, @@ -105,7 +99,7 @@ fn create_market_common( metadata, creation, market_type: options, - dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), scoring_rule, } .dispatch_bypass_filter(RawOrigin::Signed(caller.clone()).into())?; @@ -248,7 +242,7 @@ benchmarks! { )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; @@ -441,7 +435,7 @@ benchmarks! { OutcomeReport::Categorical(0u16), )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; @@ -478,7 +472,7 @@ benchmarks! { )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; @@ -531,7 +525,7 @@ benchmarks! { )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; @@ -615,8 +609,7 @@ benchmarks! { create_market { let m in 0..63; - let (caller, oracle, deadlines, metadata, creation) = - create_market_common_parameters::(MarketCreation::Permissionless)?; + let (caller, oracle, deadlines, metadata) = create_market_common_parameters::()?; let range_end = T::MaxSubsidyPeriod::get(); let period = MarketPeriod::Timestamp(T::MinSubsidyPeriod::get()..range_end); @@ -635,9 +628,9 @@ benchmarks! { period, deadlines, metadata, - creation, + MarketCreation::Permissionless, MarketType::Categorical(T::MaxCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM ) @@ -645,13 +638,13 @@ benchmarks! { let m in 0..63; let market_type = MarketType::Categorical(T::MaxCategories::get()); - let dispute_mechanism = MarketDisputeMechanism::SimpleDisputes; + let dispute_mechanism = Some(MarketDisputeMechanism::SimpleDisputes); let scoring_rule = ScoringRule::CPMM; let range_start: MomentOf = 100_000u64.saturated_into(); let range_end: MomentOf = 1_000_000u64.saturated_into(); let period = MarketPeriod::Timestamp(range_start..range_end); - let (caller, oracle, deadlines, metadata, creation) = - create_market_common_parameters::(MarketCreation::Advised)?; + let (caller, oracle, deadlines, metadata) = + create_market_common_parameters::()?; Call::::create_market { base_asset: Asset::Ztg, creator_fee: Perbill::zero(), @@ -659,7 +652,7 @@ benchmarks! { period: period.clone(), deadlines, metadata: metadata.clone(), - creation, + creation: MarketCreation::Advised, market_type: market_type.clone(), dispute_mechanism: dispute_mechanism.clone(), scoring_rule, @@ -806,7 +799,7 @@ benchmarks! { )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Court; + market.dispute_mechanism = Some(MarketDisputeMechanism::Court); Ok(()) })?; @@ -880,7 +873,7 @@ benchmarks! { )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; @@ -908,7 +901,7 @@ benchmarks! { OutcomeReport::Categorical(1u16), )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; let market = >::market(&market_id)?; @@ -927,7 +920,7 @@ benchmarks! { OutcomeReport::Categorical(1u16) )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; @@ -970,7 +963,7 @@ benchmarks! { OutcomeReport::Scalar(u128::MAX), )?; >::mutate_market(&market_id, |market| { - market.dispute_mechanism = MarketDisputeMechanism::Authorized; + market.dispute_mechanism = Some(MarketDisputeMechanism::Authorized); Ok(()) })?; let market = >::market(&market_id)?; @@ -1061,7 +1054,7 @@ benchmarks! { let call = Call::::reject_market { market_id, reject_reason }; }: { call.dispatch_bypass_filter(reject_origin)? } - report { + report_market_with_dispute_mechanism { let m in 0..63; // ensure range.start is now to get the heaviest path @@ -1104,7 +1097,41 @@ benchmarks! { ids.try_push(i.into()) }).unwrap(); } - }: _(RawOrigin::Signed(caller), market_id, outcome) + let call = Call::::report { market_id, outcome }; + }: { + call.dispatch_bypass_filter(RawOrigin::Signed(caller).into())?; + } + + report_trusted_market { + pallet_timestamp::Pallet::::set_timestamp(0u32.into()); + let start: MomentOf = >::now(); + let end: MomentOf = 1_000_000u64.saturated_into(); + let (caller, oracle, _, metadata) = create_market_common_parameters::()?; + Call::::create_market { + base_asset: Asset::Ztg, + creator_fee: Perbill::zero(), + oracle: caller.clone(), + period: MarketPeriod::Timestamp(start..end), + deadlines: Deadlines:: { + grace_period: 0u8.into(), + oracle_duration: T::MinOracleDuration::get(), + dispute_duration: 0u8.into(), + }, + metadata, + creation: MarketCreation::Permissionless, + market_type: MarketType::Categorical(3), + dispute_mechanism: None, + scoring_rule: ScoringRule::CPMM, + } + .dispatch_bypass_filter(RawOrigin::Signed(caller.clone()).into())?; + let market_id = >::latest_market_id()?; + let close_origin = T::CloseOrigin::try_successful_origin().unwrap(); + Pallet::::admin_move_market_to_closed(close_origin, market_id)?; + let outcome = OutcomeReport::Categorical(0); + let call = Call::::report { market_id, outcome }; + }: { + call.dispatch_bypass_filter(RawOrigin::Signed(caller).into())?; + } sell_complete_set { let a in (T::MinCategories::get().into())..T::MaxCategories::get().into(); diff --git a/zrml/prediction-markets/src/lib.rs b/zrml/prediction-markets/src/lib.rs index 58febff16..a8906a493 100644 --- a/zrml/prediction-markets/src/lib.rs +++ b/zrml/prediction-markets/src/lib.rs @@ -75,7 +75,7 @@ mod pallet { use zrml_market_commons::MarketCommonsPalletApi; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); pub(crate) type BalanceOf = <::AssetManager as MultiCurrency< ::AccountId, @@ -94,6 +94,8 @@ mod pallet { MomentOf, Asset>, >; + pub(crate) type ReportOf = + Report<::AccountId, ::BlockNumber>; pub type CacheSize = ConstU32<64>; pub type EditReason = BoundedVec::MaxEditReasonLen>; pub type RejectReason = BoundedVec::MaxRejectReasonLen>; @@ -364,8 +366,11 @@ mod pallet { let open_ids_len = Self::clear_auto_open(&market_id)?; let close_ids_len = Self::clear_auto_close(&market_id)?; + // Note: This is noop if the market is trusted. let (ids_len, _) = Self::clear_auto_resolve(&market_id)?; - Self::clear_dispute_mechanism(&market_id)?; + if market.dispute_mechanism.is_some() { + Self::clear_dispute_mechanism(&market_id)?; + } >::remove_market(&market_id)?; Self::deposit_event(Event::MarketDestroyed(market_id)); @@ -641,7 +646,9 @@ mod pallet { let market = >::market(&market_id)?; ensure!(market.status == MarketStatus::Reported, Error::::InvalidMarketStatus); - let weight = match market.dispute_mechanism { + let dispute_mechanism = + market.dispute_mechanism.as_ref().ok_or(Error::::NoDisputeMechanism)?; + let weight = match dispute_mechanism { MarketDisputeMechanism::Authorized => { T::Authorized::on_dispute(&market_id, &market)?; T::WeightInfo::dispute_authorized() @@ -721,7 +728,7 @@ mod pallet { deadlines: Deadlines, metadata: MultiHash, market_type: MarketType, - dispute_mechanism: MarketDisputeMechanism, + dispute_mechanism: Option, #[pallet::compact] swap_fee: BalanceOf, #[pallet::compact] amount: BalanceOf, weights: Vec, @@ -778,7 +785,7 @@ mod pallet { metadata: MultiHash, creation: MarketCreation, market_type: MarketType, - dispute_mechanism: MarketDisputeMechanism, + dispute_mechanism: Option, scoring_rule: ScoringRule, ) -> DispatchResultWithPostInfo { // TODO(#787): Handle Rikiddo benchmarks! @@ -867,7 +874,7 @@ mod pallet { deadlines: Deadlines, metadata: MultiHash, market_type: MarketType, - dispute_mechanism: MarketDisputeMechanism, + dispute_mechanism: Option, scoring_rule: ScoringRule, ) -> DispatchResultWithPostInfo { // TODO(#787): Handle Rikiddo benchmarks! @@ -1276,7 +1283,10 @@ mod pallet { /// Complexity: `O(n)`, where `n` is the number of market ids, /// which reported at the same time as the specified market. #[pallet::call_index(14)] - #[pallet::weight(T::WeightInfo::report(CacheSize::get()))] + #[pallet::weight( + T::WeightInfo::report_market_with_dispute_mechanism(CacheSize::get()) + .max(T::WeightInfo::report_trusted_market()) + )] #[transactional] pub fn report( origin: OriginFor, @@ -1284,100 +1294,30 @@ mod pallet { outcome: OutcomeReport, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin.clone())?; - let current_block = >::block_number(); let market_report = Report { at: current_block, by: sender.clone(), outcome }; - - >::mutate_market(&market_id, |market| { - ensure!(market.report.is_none(), Error::::MarketAlreadyReported); - Self::ensure_market_is_closed(market)?; - ensure!( - market.matches_outcome_report(&market_report.outcome), - Error::::OutcomeMismatch - ); - - let mut should_check_origin = false; - //NOTE: Saturating operation in following block may saturate to u32::MAX value - // but that will be the case after thousands of years time. So it is fine. - match market.period { - MarketPeriod::Block(ref range) => { - let grace_period_end = - range.end.saturating_add(market.deadlines.grace_period); - ensure!( - grace_period_end <= current_block, - Error::::NotAllowedToReportYet - ); - let oracle_duration_end = - grace_period_end.saturating_add(market.deadlines.oracle_duration); - if current_block <= oracle_duration_end { - should_check_origin = true; - } - } - MarketPeriod::Timestamp(ref range) => { - let grace_period_in_moments: MomentOf = - market.deadlines.grace_period.saturated_into::().into(); - let grace_period_in_ms = - grace_period_in_moments.saturating_mul(MILLISECS_PER_BLOCK.into()); - let grace_period_end = range.end.saturating_add(grace_period_in_ms); - let now = >::now(); - ensure!(grace_period_end <= now, Error::::NotAllowedToReportYet); - let oracle_duration_in_moments: MomentOf = - market.deadlines.oracle_duration.saturated_into::().into(); - let oracle_duration_in_ms = - oracle_duration_in_moments.saturating_mul(MILLISECS_PER_BLOCK.into()); - let oracle_duration_end = - grace_period_end.saturating_add(oracle_duration_in_ms); - if now <= oracle_duration_end { - should_check_origin = true; - } - } - } - - let sender_is_oracle = sender == market.oracle; - let origin_has_permission = T::ResolveOrigin::ensure_origin(origin).is_ok(); - let sender_is_outsider = !sender_is_oracle && !origin_has_permission; - - if should_check_origin { - ensure!( - sender_is_oracle || origin_has_permission, - Error::::ReporterNotOracle - ); - } else if sender_is_outsider { - let outsider_bond = T::OutsiderBond::get(); - - market.bonds.outsider = Some(Bond::new(sender.clone(), outsider_bond)); - - T::AssetManager::reserve_named( - &Self::reserve_id(), - Asset::Ztg, - &sender, - outsider_bond, - )?; - } - - market.report = Some(market_report.clone()); - market.status = MarketStatus::Reported; - - Ok(()) - })?; - let market = >::market(&market_id)?; - let block_after_dispute_duration = - current_block.saturating_add(market.deadlines.dispute_duration); - let ids_len = MarketIdsPerReportBlock::::try_mutate( - block_after_dispute_duration, - |ids| -> Result { - ids.try_push(market_id).map_err(|_| >::StorageOverflow)?; - Ok(ids.len() as u32) - }, - )?; - + ensure!(market.report.is_none(), Error::::MarketAlreadyReported); + Self::ensure_market_is_closed(&market)?; + ensure!( + market.matches_outcome_report(&market_report.outcome), + Error::::OutcomeMismatch + ); + let weight = if market.dispute_mechanism.is_some() { + Self::report_market_with_dispute_mechanism( + origin, + market_id, + market_report.clone(), + )? + } else { + Self::report_and_resolve_market(origin, market_id, market_report.clone())? + }; Self::deposit_event(Event::MarketReported( market_id, MarketStatus::Reported, market_report, )); - Ok(Some(T::WeightInfo::report(ids_len)).into()) + Ok(weight) } /// Sells a complete set of outcomes shares for a market. @@ -1454,13 +1394,15 @@ mod pallet { ensure_signed(origin)?; let market = >::market(&market_id)?; + let dispute_mechanism = + market.dispute_mechanism.as_ref().ok_or(Error::::NoDisputeMechanism)?; ensure!( matches!(market.status, MarketStatus::Disputed | MarketStatus::Reported), Error::::InvalidMarketStatus ); ensure!( - matches!(market.dispute_mechanism, MarketDisputeMechanism::Court), + matches!(dispute_mechanism, MarketDisputeMechanism::Court), Error::::InvalidDisputeMechanism ); @@ -1471,7 +1413,7 @@ mod pallet { let report = market.report.as_ref().ok_or(Error::::MarketIsNotReported)?; - let res_0 = match market.dispute_mechanism { + let res_0 = match dispute_mechanism { MarketDisputeMechanism::Authorized => { T::Authorized::has_failed(&market_id, &market)? } @@ -1483,7 +1425,7 @@ mod pallet { let has_failed = res_0.result; ensure!(has_failed, Error::::MarketDisputeMechanismNotFailed); - let res_1 = match market.dispute_mechanism { + let res_1 = match dispute_mechanism { MarketDisputeMechanism::Authorized => { T::Authorized::on_global_dispute(&market_id, &market)? } @@ -1821,6 +1763,10 @@ mod pallet { UnregisteredForeignAsset, /// The start of the global dispute for this market happened already. GlobalDisputeExistsAlready, + /// The market has no dispute mechanism. + NoDisputeMechanism, + /// The dispute duration is positive but the market has dispute period. + NonZeroDisputePeriodOnTrustedMarket, /// The fee is too high. FeeTooHigh, } @@ -1856,7 +1802,7 @@ mod pallet { /// \[market_id, reject_reason\] MarketRejected(MarketIdOf, RejectReason), /// A market has been reported on. \[market_id, new_market_status, reported_outcome\] - MarketReported(MarketIdOf, MarketStatus, Report), + MarketReported(MarketIdOf, MarketStatus, ReportOf), /// A market has been resolved. \[market_id, new_market_status, real_outcome\] MarketResolved(MarketIdOf, MarketStatus, OutcomeReport), /// A proposed market has been requested edit by advisor. \[market_id, edit_reason\] @@ -2222,6 +2168,12 @@ mod pallet { /// Clears this market from being stored for automatic resolution. fn clear_auto_resolve(market_id: &MarketIdOf) -> Result<(u32, u32), DispatchError> { let market = >::market(market_id)?; + // If there's no dispute mechanism, this function is noop. FIXME This is an + // anti-pattern, but it makes benchmarking easier. + let dispute_mechanism = match market.dispute_mechanism { + Some(ref result) => result, + None => return Ok((0, 0)), + }; let (ids_len, mdm_len) = match market.status { MarketStatus::Reported => { let report = market.report.ok_or(Error::::MarketIsNotReported)?; @@ -2239,7 +2191,7 @@ mod pallet { MarketStatus::Disputed => { // TODO(#782): use multiple benchmarks paths for different dispute mechanisms let ResultWithWeightInfo { result: auto_resolve_block_opt, weight: _ } = - match market.dispute_mechanism { + match dispute_mechanism { MarketDisputeMechanism::Authorized => { T::Authorized::get_auto_resolve(market_id, &market) } @@ -2266,9 +2218,11 @@ mod pallet { /// The dispute mechanism is intended to clear its own storage here. fn clear_dispute_mechanism(market_id: &MarketIdOf) -> DispatchResult { let market = >::market(market_id)?; + let dispute_mechanism = + market.dispute_mechanism.as_ref().ok_or(Error::::NoDisputeMechanism)?; // TODO(#782): use multiple benchmarks paths for different dispute mechanisms - match market.dispute_mechanism { + match dispute_mechanism { MarketDisputeMechanism::Authorized => T::Authorized::clear(market_id, &market)?, MarketDisputeMechanism::Court => T::Court::clear(market_id, &market)?, MarketDisputeMechanism::SimpleDisputes => { @@ -2397,19 +2351,27 @@ mod pallet { fn ensure_market_deadlines_are_valid( deadlines: &Deadlines, + trusted: bool, ) -> DispatchResult { ensure!( deadlines.oracle_duration >= T::MinOracleDuration::get(), Error::::OracleDurationSmallerThanMinOracleDuration ); - ensure!( - deadlines.dispute_duration >= T::MinDisputeDuration::get(), - Error::::DisputeDurationSmallerThanMinDisputeDuration - ); - ensure!( - deadlines.dispute_duration <= T::MaxDisputeDuration::get(), - Error::::DisputeDurationGreaterThanMaxDisputeDuration - ); + if trusted { + ensure!( + deadlines.dispute_duration == Zero::zero(), + Error::::NonZeroDisputePeriodOnTrustedMarket + ); + } else { + ensure!( + deadlines.dispute_duration >= T::MinDisputeDuration::get(), + Error::::DisputeDurationSmallerThanMinDisputeDuration + ); + ensure!( + deadlines.dispute_duration <= T::MaxDisputeDuration::get(), + Error::::DisputeDurationGreaterThanMaxDisputeDuration + ); + } ensure!( deadlines.grace_period <= T::MaxGracePeriod::get(), Error::::GracePeriodGreaterThanMaxGracePeriod @@ -2558,6 +2520,8 @@ mod pallet { market_id: &MarketIdOf, market: &MarketOf, ) -> Result, DispatchError> { + let dispute_mechanism = + market.dispute_mechanism.as_ref().ok_or(Error::::NoDisputeMechanism)?; let report = market.report.as_ref().ok_or(Error::::MarketIsNotReported)?; let mut weight = Weight::zero(); @@ -2568,7 +2532,7 @@ mod pallet { let imbalance_left = Self::settle_bonds(market_id, market, &resolved_outcome, report)?; - let remainder = match market.dispute_mechanism { + let remainder = match dispute_mechanism { MarketDisputeMechanism::Authorized => { let res = T::Authorized::exchange( market_id, @@ -2623,7 +2587,9 @@ mod pallet { // Try to get the outcome of the MDM. If the MDM failed to resolve, default to // the oracle's report. if resolved_outcome_option.is_none() { - resolved_outcome_option = match market.dispute_mechanism { + let dispute_mechanism = + market.dispute_mechanism.as_ref().ok_or(Error::::NoDisputeMechanism)?; + resolved_outcome_option = match dispute_mechanism { MarketDisputeMechanism::Authorized => { let res = T::Authorized::on_resolution(market_id, market)?; weight = weight.saturating_add(res.weight); @@ -2655,7 +2621,7 @@ mod pallet { market_id: &MarketIdOf, market: &MarketOf, resolved_outcome: &OutcomeReport, - report: &Report, + report: &ReportOf, ) -> Result, DispatchError> { let mut overall_imbalance = NegativeImbalanceOf::::zero(); @@ -3066,9 +3032,9 @@ mod pallet { metadata: MultiHash, creation: MarketCreation, market_type: MarketType, - dispute_mechanism: MarketDisputeMechanism, + dispute_mechanism: Option, scoring_rule: ScoringRule, - report: Option>, + report: Option>, resolved_outcome: Option, bonds: MarketBonds>, ) -> Result, DispatchError> { @@ -3090,7 +3056,7 @@ mod pallet { let MultiHash::Sha3_384(multihash) = metadata; ensure!(multihash[0] == 0x15 && multihash[1] == 0x30, >::InvalidMultihash); Self::ensure_market_period_is_valid(&period)?; - Self::ensure_market_deadlines_are_valid(&deadlines)?; + Self::ensure_market_deadlines_are_valid(&deadlines, dispute_mechanism.is_none())?; Self::ensure_market_type_is_valid(&market_type)?; if scoring_rule == ScoringRule::RikiddoSigmoidFeeMarketEma { @@ -3121,6 +3087,108 @@ mod pallet { bonds, }) } + + fn report_market_with_dispute_mechanism( + origin: OriginFor, + market_id: MarketIdOf, + report: ReportOf, + ) -> DispatchResultWithPostInfo { + let sender = ensure_signed(origin.clone())?; + >::mutate_market(&market_id, |market| { + let mut should_check_origin = false; + //NOTE: Saturating operation in following block may saturate to u32::MAX value + // but that will be the case after thousands of years time. So it is fine. + match market.period { + MarketPeriod::Block(ref range) => { + let grace_period_end = + range.end.saturating_add(market.deadlines.grace_period); + ensure!(grace_period_end <= report.at, Error::::NotAllowedToReportYet); + let oracle_duration_end = + grace_period_end.saturating_add(market.deadlines.oracle_duration); + if report.at <= oracle_duration_end { + should_check_origin = true; + } + } + MarketPeriod::Timestamp(ref range) => { + let grace_period_in_moments: MomentOf = + market.deadlines.grace_period.saturated_into::().into(); + let grace_period_in_ms = + grace_period_in_moments.saturating_mul(MILLISECS_PER_BLOCK.into()); + let grace_period_end = range.end.saturating_add(grace_period_in_ms); + let now = >::now(); + ensure!(grace_period_end <= now, Error::::NotAllowedToReportYet); + let oracle_duration_in_moments: MomentOf = + market.deadlines.oracle_duration.saturated_into::().into(); + let oracle_duration_in_ms = + oracle_duration_in_moments.saturating_mul(MILLISECS_PER_BLOCK.into()); + let oracle_duration_end = + grace_period_end.saturating_add(oracle_duration_in_ms); + if now <= oracle_duration_end { + should_check_origin = true; + } + } + } + + let sender_is_oracle = sender == market.oracle; + let origin_has_permission = T::ResolveOrigin::ensure_origin(origin).is_ok(); + let sender_is_outsider = !sender_is_oracle && !origin_has_permission; + + if should_check_origin { + ensure!( + sender_is_oracle || origin_has_permission, + Error::::ReporterNotOracle + ); + } else if sender_is_outsider { + let outsider_bond = T::OutsiderBond::get(); + + market.bonds.outsider = Some(Bond::new(sender.clone(), outsider_bond)); + + T::AssetManager::reserve_named( + &Self::reserve_id(), + Asset::Ztg, + &sender, + outsider_bond, + )?; + } + + market.report = Some(report.clone()); + market.status = MarketStatus::Reported; + + Ok(()) + })?; + + let market = >::market(&market_id)?; + let block_after_dispute_duration = + report.at.saturating_add(market.deadlines.dispute_duration); + let ids_len = MarketIdsPerReportBlock::::try_mutate( + block_after_dispute_duration, + |ids| -> Result { + ids.try_push(market_id).map_err(|_| >::StorageOverflow)?; + Ok(ids.len() as u32) + }, + )?; + + Ok(Some(T::WeightInfo::report_market_with_dispute_mechanism(ids_len)).into()) + } + + fn report_and_resolve_market( + origin: OriginFor, + market_id: MarketIdOf, + market_report: ReportOf, + ) -> DispatchResultWithPostInfo { + >::mutate_market(&market_id, |market| { + let sender = ensure_signed(origin.clone())?; + let sender_is_oracle = sender == market.oracle; + let origin_has_permission = T::ResolveOrigin::ensure_origin(origin).is_ok(); + ensure!(sender_is_oracle || origin_has_permission, Error::::ReporterNotOracle); + market.report = Some(market_report.clone()); + market.status = MarketStatus::Reported; + Ok(()) + })?; + let market = >::market(&market_id)?; + Self::on_resolution(&market_id, &market)?; + Ok(Some(T::WeightInfo::report_trusted_market()).into()) + } } fn remove_item(items: &mut BoundedVec, item: &I) { diff --git a/zrml/prediction-markets/src/migrations.rs b/zrml/prediction-markets/src/migrations.rs index 6a28e7444..e59e1294a 100644 --- a/zrml/prediction-markets/src/migrations.rs +++ b/zrml/prediction-markets/src/migrations.rs @@ -37,43 +37,54 @@ use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{traits::Saturating, Perbill}; use zeitgeist_primitives::types::{ - Asset, Bond, Deadlines, Market, MarketBonds, MarketCreation, MarketDisputeMechanism, - MarketPeriod, MarketStatus, MarketType, OutcomeReport, Report, ScoringRule, + Asset, Deadlines, Market, MarketBonds, MarketCreation, MarketDisputeMechanism, MarketPeriod, + MarketStatus, MarketType, OutcomeReport, Report, ScoringRule, }; -use zrml_market_commons::{MarketCommonsPalletApi, Pallet as MarketCommonsPallet}; +#[cfg(feature = "try-runtime")] +use zrml_market_commons::MarketCommonsPalletApi; +use zrml_market_commons::Pallet as MarketCommonsPallet; #[cfg(any(feature = "try-runtime", test))] const MARKET_COMMONS: &[u8] = b"MarketCommons"; #[cfg(any(feature = "try-runtime", test))] const MARKETS: &[u8] = b"Markets"; -const MARKET_COMMONS_REQUIRED_STORAGE_VERSION: u16 = 6; -const MARKET_COMMONS_NEXT_STORAGE_VERSION: u16 = 7; - -#[derive(Clone, Decode, Encode, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct OldMarketBonds { - pub creation: Option>, - pub oracle: Option>, - pub outsider: Option>, -} +const MARKET_COMMONS_REQUIRED_STORAGE_VERSION: u16 = 7; +const MARKET_COMMONS_NEXT_STORAGE_VERSION: u16 = 8; #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub struct OldMarket { + /// Base asset of the market. pub base_asset: A, + /// Creator of this market. pub creator: AI, + /// Creation type. pub creation: MarketCreation, - pub creator_fee: u8, + /// A fee that is charged each trade and given to the market creator. + pub creator_fee: Perbill, + /// Oracle that reports the outcome of this market. pub oracle: AI, + /// Metadata for the market, usually a content address of IPFS + /// hosted JSON. Currently limited to 66 bytes (see `MaxEncodedLen` implementation) pub metadata: Vec, + /// The type of the market. pub market_type: MarketType, + /// Market start and end pub period: MarketPeriod, + /// Market deadlines. pub deadlines: Deadlines, + /// The scoring rule used for the market. pub scoring_rule: ScoringRule, + /// The current status of the market. pub status: MarketStatus, + /// The report of the market. Only `Some` if it has been reported. pub report: Option>, + /// The resolved outcome. pub resolved_outcome: Option, + /// See [`MarketDisputeMechanism`]. pub dispute_mechanism: MarketDisputeMechanism, - pub bonds: OldMarketBonds, + /// The bonds reserved for this market. + pub bonds: MarketBonds, } type OldMarketOf = OldMarket< @@ -92,88 +103,59 @@ pub(crate) type Markets = StorageMap< OldMarketOf, >; -pub struct AddDisputeBondAndConvertCreatorFee(PhantomData); +pub struct MigrateMarkets(PhantomData); -impl OnRuntimeUpgrade - for AddDisputeBondAndConvertCreatorFee -{ +impl OnRuntimeUpgrade for MigrateMarkets { 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!( - "AddDisputeBondAndConvertCreatorFee: market-commons version is {:?}, but {:?} is \ - required", + "MigrateMarkets: market-commons version is {:?}, but {:?} is required", market_commons_version, MARKET_COMMONS_REQUIRED_STORAGE_VERSION, ); return total_weight; } - log::info!("AddDisputeBondAndConvertCreatorFee: Starting..."); - + log::info!("MigrateMarkets: Starting..."); let mut translated = 0u64; - zrml_market_commons::Markets::::translate::, _>( - |market_id, old_market| { - translated.saturating_inc(); - - let mut dispute_bond = None; - // SimpleDisputes is regarded in the following migration `MoveDataToSimpleDisputes` - if let MarketDisputeMechanism::Authorized = old_market.dispute_mechanism { - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - let old_disputes = crate::Disputes::::get(market_id); - if let Some(first_dispute) = old_disputes.first() { - let OldMarketDispute { at: _, by, outcome: _ } = first_dispute; - dispute_bond = Some(Bond::new(by.clone(), T::DisputeBond::get())); - } - } - - let new_market = Market { - base_asset: old_market.base_asset, - creator: old_market.creator, - creation: old_market.creation, - // Zero can be safely assumed here as it was hardcoded before - creator_fee: Perbill::zero(), - oracle: old_market.oracle, - metadata: old_market.metadata, - market_type: old_market.market_type, - period: old_market.period, - scoring_rule: old_market.scoring_rule, - status: old_market.status, - report: old_market.report, - resolved_outcome: old_market.resolved_outcome, - dispute_mechanism: old_market.dispute_mechanism, - deadlines: old_market.deadlines, - bonds: MarketBonds { - creation: old_market.bonds.creation, - oracle: old_market.bonds.oracle, - outsider: old_market.bonds.outsider, - dispute: dispute_bond, - }, - }; - - Some(new_market) - }, - ); - log::info!("AddDisputeBondAndConvertCreatorFee: Upgraded {} markets.", translated); + zrml_market_commons::Markets::::translate::, _>(|_, old_market| { + translated.saturating_inc(); + Some(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, + scoring_rule: old_market.scoring_rule, + status: old_market.status, + report: old_market.report, + resolved_outcome: old_market.resolved_outcome, + dispute_mechanism: Some(old_market.dispute_mechanism), + deadlines: old_market.deadlines, + bonds: old_market.bonds, + }) + }); + log::info!("MigrateMarkets: 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!("AddDisputeBondAndConvertCreatorFee: Done!"); + log::info!("MigrateMarkets: Done!"); total_weight } #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { use frame_support::pallet_prelude::Blake2_128Concat; - let old_markets = storage_key_iter::, OldMarketOf, Blake2_128Concat>( MARKET_COMMONS, MARKETS, ) .collect::>(); - let markets = Markets::::iter_keys().count() as u32; let decodable_markets = Markets::::iter_values().count() as u32; if markets != decodable_markets { @@ -183,9 +165,8 @@ impl OnRuntimeUpgrade markets ); } else { - log::info!("Markets: {}, Decodable Markets: {}", markets, decodable_markets); + log::info!("Markets: {}", markets); } - Ok(old_markets.encode()) } @@ -193,7 +174,7 @@ impl OnRuntimeUpgrade fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { let old_markets: BTreeMap, OldMarketOf> = Decode::decode(&mut &previous_state[..]) - .expect("Failed to decode state: Invalid state"); + .map_err(|_| "Failed to decode state: Invalid state")?; let new_market_count = >::market_iter().count(); assert_eq!(old_markets.len(), new_market_count); for (market_id, new_market) in >::market_iter() { @@ -203,6 +184,7 @@ impl OnRuntimeUpgrade assert_eq!(new_market.base_asset, old_market.base_asset); assert_eq!(new_market.creator, old_market.creator); assert_eq!(new_market.creation, old_market.creation); + assert_eq!(new_market.creator_fee, old_market.creator_fee); assert_eq!(new_market.oracle, old_market.oracle); assert_eq!(new_market.metadata, old_market.metadata); assert_eq!(new_market.market_type, old_market.market_type); @@ -212,36 +194,11 @@ impl OnRuntimeUpgrade assert_eq!(new_market.status, old_market.status); assert_eq!(new_market.report, old_market.report); assert_eq!(new_market.resolved_outcome, old_market.resolved_outcome); - assert_eq!(new_market.dispute_mechanism, old_market.dispute_mechanism); + assert_eq!(new_market.dispute_mechanism, Some(old_market.dispute_mechanism.clone())); assert_eq!(new_market.bonds.oracle, old_market.bonds.oracle); - assert_eq!(new_market.bonds.creation, old_market.bonds.creation); - assert_eq!(new_market.bonds.outsider, old_market.bonds.outsider); - // new fields - assert_eq!(new_market.creator_fee, Perbill::zero()); - // other dispute mechanisms are regarded in the migration after this migration - if let MarketDisputeMechanism::Authorized = new_market.dispute_mechanism { - let old_disputes = crate::Disputes::::get(market_id); - if let Some(first_dispute) = old_disputes.first() { - let OldMarketDispute { at: _, by, outcome: _ } = first_dispute; - assert_eq!( - new_market.bonds.dispute, - Some(Bond { - who: by.clone(), - value: T::DisputeBond::get(), - is_settled: false - }) - ); - } - } else { - assert_eq!(new_market.bonds.dispute, None); - } + assert_eq!(new_market.bonds, old_market.bonds); } - - log::info!( - "AddDisputeBondAndConvertCreatorFee: Market Counter post-upgrade is {}!", - new_market_count - ); - assert!(new_market_count > 0); + log::info!("MigrateMarkets: Market Counter post-upgrade is {}!", new_market_count); Ok(()) } } @@ -250,19 +207,21 @@ impl OnRuntimeUpgrade mod tests { use super::*; use crate::{ - mock::{DisputeBond, ExtBuilder, Runtime}, + mock::{ExtBuilder, Runtime}, MarketIdOf, MarketOf, }; use frame_support::{ - dispatch::fmt::Debug, migration::put_storage_value, Blake2_128Concat, StorageHasher, + dispatch::fmt::Debug, migration::put_storage_value, storage_root, Blake2_128Concat, + StateVersion, StorageHasher, }; + use test_case::test_case; use zrml_market_commons::MarketCommonsPalletApi; #[test] fn on_runtime_upgrade_increments_the_storage_version() { ExtBuilder::default().build().execute_with(|| { set_up_version(); - AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); + MigrateMarkets::::on_runtime_upgrade(); assert_eq!( StorageVersion::get::>(), MARKET_COMMONS_NEXT_STORAGE_VERSION @@ -274,51 +233,30 @@ mod tests { fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { ExtBuilder::default().build().execute_with(|| { // Don't set up chain to signal that storage is already up to date. - let (_, new_markets) = construct_old_new_tuple(None); + let (_, new_markets) = construct_old_new_tuple(MarketDisputeMechanism::Court); populate_test_data::, MarketOf>( MARKET_COMMONS, MARKETS, new_markets.clone(), ); - AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); - let actual = >::market(&0u128).unwrap(); - assert_eq!(actual, new_markets[0]); - }); - } - - #[test] - fn on_runtime_upgrade_correctly_updates_markets_with_none_disputor() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let (old_markets, new_markets) = construct_old_new_tuple(None); - populate_test_data::, OldMarketOf>( - MARKET_COMMONS, - MARKETS, - old_markets, - ); - AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); - let actual = >::market(&0u128).unwrap(); - assert_eq!(actual, new_markets[0]); + let tmp = storage_root(StateVersion::V1); + MigrateMarkets::::on_runtime_upgrade(); + assert_eq!(tmp, storage_root(StateVersion::V1)); }); } - #[test] - fn on_runtime_upgrade_correctly_updates_markets_with_some_disputor() { + #[test_case(MarketDisputeMechanism::Authorized)] + #[test_case(MarketDisputeMechanism::Court)] + fn on_runtime_upgrade_correctly_updates_markets(dispute_mechanism: MarketDisputeMechanism) { ExtBuilder::default().build().execute_with(|| { set_up_version(); - let mut disputes = crate::Disputes::::get(0); - let disputor = crate::mock::EVE; - let dispute = - OldMarketDispute { at: 0, by: disputor, outcome: OutcomeReport::Categorical(0u16) }; - disputes.try_push(dispute).unwrap(); - crate::Disputes::::insert(0, disputes); - let (old_markets, new_markets) = construct_old_new_tuple(Some(disputor)); + let (old_markets, new_markets) = construct_old_new_tuple(dispute_mechanism); populate_test_data::, OldMarketOf>( MARKET_COMMONS, MARKETS, old_markets, ); - AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); + MigrateMarkets::::on_runtime_upgrade(); let actual = >::market(&0u128).unwrap(); assert_eq!(actual, new_markets[0]); }); @@ -330,12 +268,11 @@ mod tests { } fn construct_old_new_tuple( - disputor: Option, + dispute_mechanism: MarketDisputeMechanism, ) -> (Vec>, Vec>) { let base_asset = Asset::Ztg; let creator = 999; - let old_creator_fee = 0; - let new_creator_fee = Perbill::zero(); + let creator_fee = Perbill::from_parts(1); let oracle = 2; let metadata = vec![3, 4, 5]; let market_type = MarketType::Categorical(6); @@ -345,26 +282,14 @@ mod tests { let creation = MarketCreation::Permissionless; let report = None; let resolved_outcome = None; - let dispute_mechanism = MarketDisputeMechanism::Authorized; let deadlines = Deadlines::default(); - let old_bonds = OldMarketBonds { - creation: Some(Bond::new(creator, ::ValidityBond::get())), - oracle: Some(Bond::new(creator, ::OracleBond::get())), - outsider: Some(Bond::new(creator, ::OutsiderBond::get())), - }; - let dispute_bond = disputor.map(|disputor| Bond::new(disputor, DisputeBond::get())); - let new_bonds = MarketBonds { - creation: Some(Bond::new(creator, ::ValidityBond::get())), - oracle: Some(Bond::new(creator, ::OracleBond::get())), - outsider: Some(Bond::new(creator, ::OutsiderBond::get())), - dispute: dispute_bond, - }; + let bonds: MarketBonds<_, _> = Default::default(); let old_market = OldMarket { base_asset, creator, creation: creation.clone(), - creator_fee: old_creator_fee, + creator_fee, oracle, metadata: metadata.clone(), market_type: market_type.clone(), @@ -375,13 +300,13 @@ mod tests { resolved_outcome: resolved_outcome.clone(), dispute_mechanism: dispute_mechanism.clone(), deadlines, - bonds: old_bonds, + bonds: bonds.clone(), }; let new_market = Market { base_asset, creator, creation, - creator_fee: new_creator_fee, + creator_fee, oracle, metadata, market_type, @@ -390,9 +315,9 @@ mod tests { status, report, resolved_outcome, - dispute_mechanism, + dispute_mechanism: Some(dispute_mechanism), deadlines, - bonds: new_bonds, + bonds, }; (vec![old_market], vec![new_market]) } @@ -412,404 +337,6 @@ mod tests { } } -use frame_support::dispatch::EncodeLike; -use sp_runtime::SaturatedConversion; -use zeitgeist_primitives::types::{MarketDispute, OldMarketDispute}; - -const PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION: u16 = 6; -const PREDICTION_MARKETS_NEXT_STORAGE_VERSION: u16 = 7; - -#[cfg(feature = "try-runtime")] -type OldDisputesOf = frame_support::BoundedVec< - OldMarketDispute< - ::AccountId, - ::BlockNumber, - >, - ::MaxDisputes, ->; - -pub struct MoveDataToSimpleDisputes(PhantomData); - -impl OnRuntimeUpgrade - for MoveDataToSimpleDisputes -where - ::MarketId: EncodeLike< - <::MarketCommons as MarketCommonsPalletApi>::MarketId, - >, -{ - fn on_runtime_upgrade() -> Weight { - use orml_traits::NamedMultiReservableCurrency; - - let mut total_weight = T::DbWeight::get().reads(1); - let pm_version = StorageVersion::get::>(); - if pm_version != PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION { - log::info!( - "MoveDataToSimpleDisputes: prediction-markets version is {:?}, but {:?} is \ - required", - pm_version, - PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION, - ); - return total_weight; - } - log::info!("MoveDataToSimpleDisputes: Starting..."); - - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - - // important drain disputes storage item from prediction markets pallet - for (market_id, old_disputes) in crate::Disputes::::drain() { - total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - if let Ok(market) = >::market(&market_id) { - match market.dispute_mechanism { - MarketDisputeMechanism::Authorized => continue, - // just transform SimpleDispute disputes - MarketDisputeMechanism::SimpleDisputes => (), - MarketDisputeMechanism::Court => continue, - } - } else { - log::warn!( - "MoveDataToSimpleDisputes: Could not find market with market id {:?}", - market_id - ); - } - - total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); - let mut new_disputes = zrml_simple_disputes::Disputes::::get(market_id); - for (i, old_dispute) in old_disputes.iter().enumerate() { - let bond = zrml_simple_disputes::default_outcome_bond::(i); - let new_dispute = MarketDispute { - at: old_dispute.at, - by: old_dispute.by.clone(), - outcome: old_dispute.outcome.clone(), - bond, - }; - let res = new_disputes.try_push(new_dispute); - if res.is_err() { - log::error!( - "MoveDataToSimpleDisputes: Could not push dispute for market id {:?}", - market_id - ); - } - - // switch to new reserve identifier for simple disputes - let sd_reserve_id = >::reserve_id(); - let pm_reserve_id = >::reserve_id(); - - // charge weight defensivly for unreserve_named - // https://github.com/open-web3-stack/open-runtime-module-library/blob/24f0a8b6e04e1078f70d0437fb816337cdf4f64c/tokens/src/lib.rs#L1516-L1547 - total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(4, 3)); - let reserved_balance = ::AssetManager::reserved_balance_named( - &pm_reserve_id, - Asset::Ztg, - &old_dispute.by, - ); - if reserved_balance < bond.saturated_into::().saturated_into() { - // warns for battery station market id 386 - // https://discord.com/channels/737780518313000960/817041223201587230/958682619413934151 - log::warn!( - "MoveDataToSimpleDisputes: Could not unreserve {:?} for {:?} because \ - reserved balance is only {:?}. Market id: {:?}", - bond, - old_dispute.by, - reserved_balance, - market_id, - ); - } - ::AssetManager::unreserve_named( - &pm_reserve_id, - Asset::Ztg, - &old_dispute.by, - bond.saturated_into::().saturated_into(), - ); - - // charge weight defensivly for reserve_named - // https://github.com/open-web3-stack/open-runtime-module-library/blob/24f0a8b6e04e1078f70d0437fb816337cdf4f64c/tokens/src/lib.rs#L1486-L1499 - total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(3, 3)); - let res = ::AssetManager::reserve_named( - &sd_reserve_id, - Asset::Ztg, - &old_dispute.by, - bond.saturated_into::().saturated_into(), - ); - if res.is_err() { - log::error!( - "MoveDataToSimpleDisputes: Could not reserve bond for dispute caller {:?} \ - and market id {:?}", - old_dispute.by, - market_id - ); - } - } - - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - zrml_simple_disputes::Disputes::::insert(market_id, new_disputes); - } - - StorageVersion::new(PREDICTION_MARKETS_NEXT_STORAGE_VERSION).put::>(); - total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("MoveDataToSimpleDisputes: Done!"); - total_weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - log::info!("MoveDataToSimpleDisputes: Start pre_upgrade!"); - - let old_disputes = crate::Disputes::::iter().collect::>(); - Ok(old_disputes.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(previous_state: Vec) -> Result<(), &'static str> { - let old_disputes: BTreeMap, OldDisputesOf> = - Decode::decode(&mut &previous_state[..]) - .expect("Failed to decode state: Invalid state"); - - log::info!("MoveDataToSimpleDisputes: (post_upgrade) Start first try-runtime part!"); - - for (market_id, o) in old_disputes.iter() { - let market = >::market(market_id) - .expect(&format!("Market for market id {:?} not found", market_id)[..]); - - // market id is a reference, but we need the raw value to encode with the where clause - let disputes = zrml_simple_disputes::Disputes::::get(*market_id); - - match market.dispute_mechanism { - MarketDisputeMechanism::Authorized => { - let simple_disputes_count = disputes.iter().count(); - assert_eq!(simple_disputes_count, 0); - continue; - } - MarketDisputeMechanism::SimpleDisputes => { - let new_count = disputes.iter().count(); - let old_count = o.iter().count(); - assert_eq!(new_count, old_count); - } - MarketDisputeMechanism::Court => { - panic!("Court should not be contained at all.") - } - } - } - - log::info!("MoveDataToSimpleDisputes: (post_upgrade) Start second try-runtime part!"); - - assert!(crate::Disputes::::iter().count() == 0); - - for (market_id, new_disputes) in zrml_simple_disputes::Disputes::::iter() { - let old_disputes = old_disputes - .get(&market_id.saturated_into::().saturated_into()) - .expect(&format!("Disputes for market {:?} not found", market_id)[..]); - - let market = ::MarketCommons::market(&market_id) - .expect(&format!("Market for market id {:?} not found", market_id)[..]); - match market.dispute_mechanism { - MarketDisputeMechanism::Authorized => { - panic!("Authorized should not be contained in simple disputes."); - } - MarketDisputeMechanism::SimpleDisputes => (), - MarketDisputeMechanism::Court => { - panic!("Court should not be contained in simple disputes."); - } - } - - for (i, new_dispute) in new_disputes.iter().enumerate() { - let old_dispute = - old_disputes.get(i).expect(&format!("Dispute at index {} not found", i)[..]); - assert_eq!(new_dispute.at, old_dispute.at); - assert_eq!(new_dispute.by, old_dispute.by); - assert_eq!(new_dispute.outcome, old_dispute.outcome); - assert_eq!(new_dispute.bond, zrml_simple_disputes::default_outcome_bond::(i)); - } - } - - log::info!("MoveDataToSimpleDisputes: Done! (post_upgrade)"); - Ok(()) - } -} - -#[cfg(test)] -mod tests_simple_disputes_migration { - use super::*; - use crate::{ - mock::{DisputeBond, ExtBuilder, Runtime}, - MarketOf, - }; - use orml_traits::NamedMultiReservableCurrency; - use zrml_market_commons::MarketCommonsPalletApi; - - #[test] - fn on_runtime_upgrade_increments_the_storage_version() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - MoveDataToSimpleDisputes::::on_runtime_upgrade(); - assert_eq!( - StorageVersion::get::>(), - PREDICTION_MARKETS_NEXT_STORAGE_VERSION - ); - }); - } - - #[test] - fn on_runtime_upgrade_is_noop_if_versions_are_not_correct() { - ExtBuilder::default().build().execute_with(|| { - // Don't set up chain to signal that storage is already up to date. - let market_id = 0u128; - let mut disputes = zrml_simple_disputes::Disputes::::get(market_id); - let dispute = MarketDispute { - at: 42u64, - by: 0u128, - outcome: OutcomeReport::Categorical(0u16), - bond: DisputeBond::get(), - }; - disputes.try_push(dispute.clone()).unwrap(); - zrml_simple_disputes::Disputes::::insert(market_id, disputes); - let market = get_market(MarketDisputeMechanism::SimpleDisputes); - >::push_market(market).unwrap(); - - MoveDataToSimpleDisputes::::on_runtime_upgrade(); - - let actual = zrml_simple_disputes::Disputes::::get(0); - assert_eq!(actual, vec![dispute]); - }); - } - - #[test] - fn on_runtime_upgrade_correctly_updates_simple_disputes() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let market_id = 0u128; - - let mut disputes = crate::Disputes::::get(0); - for i in 0..::MaxDisputes::get() { - let dispute = OldMarketDispute { - at: i as u64 + 42u64, - by: i as u128, - outcome: OutcomeReport::Categorical(i), - }; - disputes.try_push(dispute).unwrap(); - } - crate::Disputes::::insert(market_id, disputes); - let market = get_market(MarketDisputeMechanism::SimpleDisputes); - >::push_market(market).unwrap(); - - MoveDataToSimpleDisputes::::on_runtime_upgrade(); - - let mut disputes = zrml_simple_disputes::Disputes::::get(market_id); - for i in 0..::MaxDisputes::get() { - let dispute = disputes.get_mut(i as usize).unwrap(); - - assert_eq!(dispute.at, i as u64 + 42u64); - assert_eq!(dispute.by, i as u128); - assert_eq!(dispute.outcome, OutcomeReport::Categorical(i)); - - let bond = zrml_simple_disputes::default_outcome_bond::(i as usize); - assert_eq!(dispute.bond, bond); - } - }); - } - - #[test] - fn on_runtime_upgrade_correctly_updates_reserve_ids() { - ExtBuilder::default().build().execute_with(|| { - set_up_version(); - let market_id = 0u128; - - let mut disputes = crate::Disputes::::get(0); - for i in 0..::MaxDisputes::get() { - let dispute = OldMarketDispute { - at: i as u64 + 42u64, - by: i as u128, - outcome: OutcomeReport::Categorical(i), - }; - let bond = zrml_simple_disputes::default_outcome_bond::(i.into()); - let pm_reserve_id = crate::Pallet::::reserve_id(); - let res = ::AssetManager::reserve_named( - &pm_reserve_id, - Asset::Ztg, - &dispute.by, - bond.saturated_into::().saturated_into(), - ); - assert!(res.is_ok()); - disputes.try_push(dispute).unwrap(); - } - crate::Disputes::::insert(market_id, disputes); - let market = get_market(MarketDisputeMechanism::SimpleDisputes); - >::push_market(market).unwrap(); - - MoveDataToSimpleDisputes::::on_runtime_upgrade(); - - let mut disputes = zrml_simple_disputes::Disputes::::get(market_id); - for i in 0..::MaxDisputes::get() { - let dispute = disputes.get_mut(i as usize).unwrap(); - - let sd_reserve_id = zrml_simple_disputes::Pallet::::reserve_id(); - let reserved_balance = - ::AssetManager::reserved_balance_named( - &sd_reserve_id, - Asset::Ztg, - &dispute.by, - ); - let bond = zrml_simple_disputes::default_outcome_bond::(i.into()); - assert_eq!(reserved_balance, bond); - assert!(reserved_balance > 0); - - let pm_reserve_id = crate::Pallet::::reserve_id(); - let reserved_balance = - ::AssetManager::reserved_balance_named( - &pm_reserve_id, - Asset::Ztg, - &dispute.by, - ); - assert_eq!(reserved_balance, 0); - } - }); - } - - fn set_up_version() { - StorageVersion::new(PREDICTION_MARKETS_REQUIRED_STORAGE_VERSION) - .put::>(); - } - - fn get_market(dispute_mechanism: MarketDisputeMechanism) -> MarketOf { - let base_asset = Asset::Ztg; - let creator = 999; - let creator_fee = Perbill::zero(); - let oracle = 2; - let metadata = vec![3, 4, 5]; - let market_type = MarketType::Categorical(6); - let period = MarketPeriod::Block(7..8); - let scoring_rule = ScoringRule::CPMM; - let status = MarketStatus::Disputed; - let creation = MarketCreation::Permissionless; - let report = None; - let resolved_outcome = None; - let deadlines = Deadlines::default(); - let bonds = MarketBonds { - creation: Some(Bond::new(creator, ::ValidityBond::get())), - oracle: Some(Bond::new(creator, ::OracleBond::get())), - outsider: None, - dispute: None, - }; - - Market { - base_asset, - creator, - creation, - creator_fee, - oracle, - metadata, - market_type, - period, - scoring_rule, - status, - report, - resolved_outcome, - dispute_mechanism, - deadlines, - bonds, - } - } -} - // We use these utilities to prevent having to make the swaps pallet a dependency of // prediciton-markets. The calls are based on the implementation of `StorageVersion`, found here: // https://github.com/paritytech/substrate/blob/bc7a1e6c19aec92bfa247d8ca68ec63e07061032/frame/support/src/traits/metadata.rs#L168-L230 diff --git a/zrml/prediction-markets/src/tests.rs b/zrml/prediction-markets/src/tests.rs index 9b79c33e1..ab152fb8d 100644 --- a/zrml/prediction-markets/src/tests.rs +++ b/zrml/prediction-markets/src/tests.rs @@ -48,7 +48,7 @@ use zeitgeist_primitives::{ types::{ AccountIdTest, Asset, Balance, BlockNumber, Bond, Deadlines, Market, MarketBonds, MarketCreation, MarketDisputeMechanism, MarketId, MarketPeriod, MarketStatus, MarketType, - Moment, MultiHash, OutcomeReport, PoolStatus, ScalarPosition, ScoringRule, + Moment, MultiHash, OutcomeReport, PoolStatus, Report, ScalarPosition, ScoringRule, }, }; use zrml_global_disputes::{ @@ -115,7 +115,7 @@ fn simple_create_categorical_market( gen_metadata(2), creation, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), scoring_rule )); } @@ -136,7 +136,7 @@ fn simple_create_scalar_market( gen_metadata(2), creation, MarketType::Scalar(100..=200), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), scoring_rule )); } @@ -187,7 +187,7 @@ fn admin_move_market_to_closed_successfully_closes_market_and_sets_end_timestamp gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let market_id = 0; @@ -263,7 +263,7 @@ fn admin_move_market_to_closed_correctly_clears_auto_open_and_close_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -277,7 +277,7 @@ fn admin_move_market_to_closed_correctly_clears_auto_open_and_close_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -291,7 +291,7 @@ fn admin_move_market_to_closed_correctly_clears_auto_open_and_close_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -323,7 +323,7 @@ fn create_scalar_market_fails_on_invalid_range(range: RangeInclusive) { gen_metadata(2), MarketCreation::Permissionless, MarketType::Scalar(range), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::InvalidOutcomeRange @@ -350,7 +350,7 @@ fn create_market_fails_on_min_dispute_period() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::DisputeDurationSmallerThanMinDisputeDuration @@ -377,7 +377,7 @@ fn create_market_fails_on_min_oracle_duration() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::OracleDurationSmallerThanMinOracleDuration @@ -404,7 +404,7 @@ fn create_market_fails_on_max_dispute_period() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::DisputeDurationGreaterThanMaxDisputeDuration @@ -431,7 +431,7 @@ fn create_market_fails_on_max_grace_period() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::GracePeriodGreaterThanMaxGracePeriod @@ -458,7 +458,7 @@ fn create_market_fails_on_max_oracle_duration() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::OracleDurationGreaterThanMaxOracleDuration @@ -489,7 +489,7 @@ fn create_market_with_foreign_assets() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::InvalidBaseAsset, @@ -506,7 +506,7 @@ fn create_market_with_foreign_assets() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, ), Error::::UnregisteredForeignAsset, @@ -522,7 +522,7 @@ fn create_market_with_foreign_assets() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); let market = MarketCommons::market(&0).unwrap(); @@ -1024,7 +1024,7 @@ fn admin_destroy_market_correctly_cleans_up_accounts() { get_deadlines(), gen_metadata(50), MarketType::Categorical(3), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), swap_fee, LIQUIDITY, vec![::MinWeight::get(); 3], @@ -1090,7 +1090,7 @@ fn admin_destroy_market_correctly_clears_auto_open_and_close_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1104,7 +1104,7 @@ fn admin_destroy_market_correctly_clears_auto_open_and_close_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1118,7 +1118,7 @@ fn admin_destroy_market_correctly_clears_auto_open_and_close_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1313,7 +1313,7 @@ fn it_does_not_create_market_with_too_few_categories() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(::MinCategories::get() - 1), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM ), Error::::NotEnoughCategories @@ -1335,7 +1335,7 @@ fn it_does_not_create_market_with_too_many_categories() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(::MaxCategories::get() + 1), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM ), Error::::TooManyCategories @@ -1816,7 +1816,7 @@ fn on_market_open_successfully_auto_opens_market_pool_with_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1848,7 +1848,7 @@ fn on_market_close_successfully_auto_closes_market_with_blocks() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1887,7 +1887,7 @@ fn on_market_open_successfully_auto_opens_market_with_timestamps() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1922,7 +1922,7 @@ fn on_market_close_successfully_auto_closes_market_with_timestamps() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1969,7 +1969,7 @@ fn on_market_open_successfully_auto_opens_multiple_markets_after_stall() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -1983,7 +1983,7 @@ fn on_market_open_successfully_auto_opens_multiple_markets_after_stall() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -2016,7 +2016,7 @@ fn on_market_close_successfully_auto_closes_multiple_markets_after_stall() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -2030,7 +2030,7 @@ fn on_market_close_successfully_auto_closes_multiple_markets_after_stall() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 0, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -2070,7 +2070,7 @@ fn on_initialize_skips_the_genesis_block() { get_deadlines(), gen_metadata(50), MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 123, LIQUIDITY, vec![::MinWeight::get(); category_count.into()], @@ -2165,7 +2165,7 @@ fn create_categorical_market_fails_if_market_begin_is_equal_to_end() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, ), Error::::InvalidMarketPeriod, @@ -2196,7 +2196,7 @@ fn create_categorical_market_fails_if_market_period_is_invalid( gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, ), Error::::InvalidMarketPeriod, @@ -2220,7 +2220,7 @@ fn create_categorical_market_fails_if_end_is_not_far_enough_ahead() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, ), Error::::InvalidMarketPeriod, @@ -2238,7 +2238,7 @@ fn create_categorical_market_fails_if_end_is_not_far_enough_ahead() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, ), Error::::InvalidMarketPeriod, @@ -2580,7 +2580,7 @@ fn it_allows_only_oracle_to_report_the_outcome_of_a_market_during_oracle_duratio gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); @@ -2739,7 +2739,7 @@ fn dispute_fails_disputed_already() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); @@ -2780,7 +2780,7 @@ fn dispute_fails_if_market_not_reported() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); @@ -2815,7 +2815,7 @@ fn dispute_reserves_dispute_bond() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); @@ -2861,7 +2861,7 @@ fn dispute_updates_market() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); @@ -2908,7 +2908,7 @@ fn dispute_emits_event() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); @@ -3209,7 +3209,7 @@ fn it_resolves_a_disputed_court_market() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Court, + Some(MarketDisputeMechanism::Court), ScoringRule::CPMM, )); @@ -3477,7 +3477,7 @@ fn it_appeals_a_court_market_to_global_dispute() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Court, + Some(MarketDisputeMechanism::Court), ScoringRule::CPMM, )); @@ -3597,7 +3597,7 @@ fn start_global_dispute_fails_on_wrong_mdm() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MaxDisputes::get() + 1), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); let market_id = MarketCommons::latest_market_id().unwrap(); @@ -3691,7 +3691,7 @@ fn create_market_and_deploy_assets_results_in_expected_balances_and_pool_params( get_deadlines(), metadata, market_type, - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), swap_fee, amount, weights, @@ -3918,7 +3918,7 @@ fn only_creator_can_edit_market() { get_deadlines(), gen_metadata(2), MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM ), Error::::EditorNotCreator @@ -3960,7 +3960,7 @@ fn edit_cycle_for_proposed_markets() { get_deadlines(), gen_metadata(2), MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let edited_market = MarketCommons::market(&0).expect("Market not found"); @@ -4007,7 +4007,7 @@ fn edit_market_with_foreign_asset() { get_deadlines(), gen_metadata(2), MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM ), Error::::UnregisteredForeignAsset @@ -4023,7 +4023,7 @@ fn edit_market_with_foreign_asset() { get_deadlines(), gen_metadata(2), MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM ), Error::::InvalidBaseAsset, @@ -4038,7 +4038,7 @@ fn edit_market_with_foreign_asset() { get_deadlines(), gen_metadata(2), MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let market = MarketCommons::market(&0).unwrap(); @@ -4060,7 +4060,7 @@ fn the_entire_market_lifecycle_works_with_timestamps() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); @@ -4100,7 +4100,7 @@ fn full_scalar_market_lifecycle() { gen_metadata(3), MarketCreation::Permissionless, MarketType::Scalar(10..=30), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); @@ -4309,7 +4309,7 @@ fn market_resolve_does_not_hold_liquidity_withdraw() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); deploy_swap_pool(MarketCommons::market(&0).unwrap(), 0).unwrap(); @@ -4351,7 +4351,7 @@ fn authorized_correctly_resolves_disputed_market() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(::MinCategories::get()), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); assert_ok!(PredictionMarkets::buy_complete_set(RuntimeOrigin::signed(CHARLIE), 0, CENT)); @@ -4497,7 +4497,7 @@ fn approve_market_correctly_unreserves_advisory_bond() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); let market_id = 0; @@ -4535,7 +4535,7 @@ fn deploy_swap_pool_correctly_sets_weight_of_base_asset() { get_deadlines(), gen_metadata(50), MarketType::Categorical(3), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), 1, LIQUIDITY, weights, @@ -4563,7 +4563,7 @@ fn deploy_swap_pool_for_market_returns_error_if_weights_is_too_short() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let amount = 123 * BASE; @@ -4601,7 +4601,7 @@ fn deploy_swap_pool_for_market_returns_error_if_weights_is_too_long() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(category_count), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let amount = 123 * BASE; @@ -4642,7 +4642,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); let alice_balance_before = Balances::free_balance(ALICE); @@ -4688,7 +4688,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); let alice_balance_before = Balances::free_balance(ALICE); @@ -4754,7 +4754,7 @@ fn outsider_reports_wrong_outcome() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); @@ -4833,7 +4833,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_approved_advised_ma gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); assert_ok!(PredictionMarkets::approve_market(RuntimeOrigin::signed(SUDO), 0)); @@ -4879,7 +4879,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_approved_advised_ma gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); assert_ok!(PredictionMarkets::approve_market(RuntimeOrigin::signed(SUDO), 0)); @@ -4926,7 +4926,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); let alice_balance_before = Balances::free_balance(ALICE); @@ -4977,7 +4977,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_approved_advised_ma gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); assert_ok!(PredictionMarkets::approve_market(RuntimeOrigin::signed(SUDO), 0)); @@ -5029,7 +5029,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); let alice_balance_before = Balances::free_balance(ALICE); @@ -5089,7 +5089,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_advised_approved_ma gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); assert_ok!(PredictionMarkets::approve_market(RuntimeOrigin::signed(SUDO), 0)); @@ -5147,7 +5147,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); @@ -5219,7 +5219,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_advised_approved_ma gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM, )); @@ -5286,7 +5286,7 @@ fn report_fails_on_market_state_proposed() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); assert_noop!( @@ -5309,7 +5309,7 @@ fn report_fails_on_market_state_closed_for_advised_market() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); assert_noop!( @@ -5332,7 +5332,7 @@ fn report_fails_on_market_state_collecting_subsidy() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::RikiddoSigmoidFeeMarketEma )); assert_noop!( @@ -5355,7 +5355,7 @@ fn report_fails_on_market_state_insufficient_subsidy() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::RikiddoSigmoidFeeMarketEma )); let _ = MarketCommons::mutate_market(&0, |market| { @@ -5382,7 +5382,7 @@ fn report_fails_on_market_state_active() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); assert_noop!( @@ -5405,7 +5405,7 @@ fn report_fails_on_market_state_suspended() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let _ = MarketCommons::mutate_market(&0, |market| { @@ -5432,7 +5432,7 @@ fn report_fails_on_market_state_resolved() { gen_metadata(2), MarketCreation::Advised, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let _ = MarketCommons::mutate_market(&0, |market| { @@ -5459,7 +5459,7 @@ fn report_fails_if_reporter_is_not_the_oracle() { gen_metadata(2), MarketCreation::Permissionless, MarketType::Categorical(2), - MarketDisputeMechanism::SimpleDisputes, + Some(MarketDisputeMechanism::SimpleDisputes), ScoringRule::CPMM )); let market = MarketCommons::market(&0).unwrap(); @@ -5500,7 +5500,7 @@ fn create_market_succeeds_if_market_duration_is_maximal_in_blocks() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); }); @@ -5528,7 +5528,7 @@ fn create_market_suceeds_if_market_duration_is_maximal_in_moments() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, )); }); @@ -5556,7 +5556,7 @@ fn create_market_fails_if_market_duration_is_too_long_in_blocks() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, ), crate::Error::::MarketDurationTooLong, @@ -5587,7 +5587,7 @@ fn create_market_fails_if_market_duration_is_too_long_in_moments() { gen_metadata(0), MarketCreation::Permissionless, MarketType::Categorical(3), - MarketDisputeMechanism::Authorized, + Some(MarketDisputeMechanism::Authorized), ScoringRule::CPMM, ), crate::Error::::MarketDurationTooLong, @@ -5635,7 +5635,7 @@ fn create_market_sets_the_correct_market_parameters_and_reserves_the_correct_amo let metadata = gen_metadata(0x99); let MultiHash::Sha3_384(multihash) = metadata; let market_type = MarketType::Categorical(7); - let dispute_mechanism = MarketDisputeMechanism::Authorized; + let dispute_mechanism = Some(MarketDisputeMechanism::Authorized); let creator_fee = Perbill::from_parts(1); assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(creator), @@ -5690,7 +5690,7 @@ fn create_cpmm_market_and_deploy_assets_sets_the_correct_market_parameters_and_r let MultiHash::Sha3_384(multihash) = metadata; let category_count = 7; let market_type = MarketType::Categorical(category_count); - let dispute_mechanism = MarketDisputeMechanism::Authorized; + let dispute_mechanism = Some(MarketDisputeMechanism::Authorized); let creator_fee = Perbill::from_parts(1); let lp_fee = 0; let weight = ::MinWeight::get(); @@ -5747,7 +5747,7 @@ fn create_market_functions_respect_fee_boundaries() { let scoring_rule = ScoringRule::CPMM; let market_type = MarketType::Categorical(category_count); let creation_type = MarketCreation::Permissionless; - let dispute_mechanism = MarketDisputeMechanism::Authorized; + let dispute_mechanism = Some(MarketDisputeMechanism::Authorized); let lp_fee = 0; assert_ok!(PredictionMarkets::create_market( @@ -5816,6 +5816,81 @@ fn create_market_functions_respect_fee_boundaries() { }); } +#[test] +fn create_market_fails_on_trusted_market_with_non_zero_dispute_period() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + PredictionMarkets::create_market( + RuntimeOrigin::signed(ALICE), + Asset::Ztg, + Perbill::zero(), + BOB, + MarketPeriod::Block(1..2), + Deadlines { + grace_period: 1, + oracle_duration: ::MinOracleDuration::get() + 2, + dispute_duration: ::MinDisputeDuration::get() + 3, + }, + gen_metadata(0x99), + MarketCreation::Permissionless, + MarketType::Categorical(3), + None, + ScoringRule::CPMM, + ), + Error::::NonZeroDisputePeriodOnTrustedMarket + ); + }); +} + +#[test] +fn trusted_market_complete_lifecycle() { + ExtBuilder::default().build().execute_with(|| { + let end = 3; + assert_ok!(PredictionMarkets::create_market( + RuntimeOrigin::signed(ALICE), + Asset::Ztg, + Perbill::zero(), + BOB, + MarketPeriod::Block(0..end), + Deadlines { + grace_period: 0, + oracle_duration: ::MinOracleDuration::get(), + dispute_duration: Zero::zero(), + }, + gen_metadata(0x99), + MarketCreation::Permissionless, + MarketType::Categorical(3), + None, + ScoringRule::CPMM, + )); + let market_id = 0; + assert_ok!(PredictionMarkets::buy_complete_set( + RuntimeOrigin::signed(FRED), + market_id, + BASE + )); + run_to_block(end); + let outcome = OutcomeReport::Categorical(1); + assert_ok!(PredictionMarkets::report( + RuntimeOrigin::signed(BOB), + market_id, + outcome.clone() + )); + let market = MarketCommons::market(&market_id).unwrap(); + assert_eq!(market.status, MarketStatus::Resolved); + assert_eq!(market.report, Some(Report { at: end, by: BOB, outcome: outcome.clone() })); + assert_eq!(market.resolved_outcome, Some(outcome)); + assert_eq!(market.dispute_mechanism, None); + assert!(market.bonds.oracle.unwrap().is_settled); + assert_eq!(market.bonds.outsider, None); + assert_eq!(market.bonds.dispute, None); + assert_ok!(PredictionMarkets::redeem_shares(RuntimeOrigin::signed(FRED), market_id)); + // Ensure that we don't accidentally leave any artifacts. + assert!(MarketIdsPerDisputeBlock::::iter().next().is_none()); + assert!(MarketIdsPerReportBlock::::iter().next().is_none()); + }); +} + fn deploy_swap_pool( market: Market>, market_id: u128, diff --git a/zrml/prediction-markets/src/weights.rs b/zrml/prediction-markets/src/weights.rs index 43e0092af..d7f01477a 100644 --- a/zrml/prediction-markets/src/weights.rs +++ b/zrml/prediction-markets/src/weights.rs @@ -72,7 +72,8 @@ pub trait WeightInfoZeitgeist { fn redeem_shares_categorical() -> Weight; fn redeem_shares_scalar() -> Weight; fn reject_market(c: u32, o: u32, r: u32) -> Weight; - fn report(m: u32) -> Weight; + fn report_market_with_dispute_mechanism(m: u32) -> Weight; + fn report_trusted_market() -> Weight; fn sell_complete_set(a: u32) -> Weight; fn start_subsidy(a: u32) -> Weight; fn market_status_manager(b: u32, f: u32) -> Weight; @@ -415,11 +416,14 @@ impl WeightInfoZeitgeist for WeightInfo { // Storage: MarketCommons Markets (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: PredictionMarkets MarketIdsPerReportBlock (r:1 w:1) - fn report(_m: u32) -> Weight { + fn report_market_with_dispute_mechanism(_m: u32) -> Weight { Weight::from_ref_time(69_185_134) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } + fn report_trusted_market() -> Weight { + Weight::from_ref_time(123) + } // Storage: MarketCommons Markets (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Tokens Accounts (r:2 w:2) diff --git a/zrml/simple-disputes/src/lib.rs b/zrml/simple-disputes/src/lib.rs index 8304fa5ce..b89ee5713 100644 --- a/zrml/simple-disputes/src/lib.rs +++ b/zrml/simple-disputes/src/lib.rs @@ -186,10 +186,7 @@ mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let market = T::MarketCommons::market(&market_id)?; - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(&market)?; ensure!(market.status == MarketStatus::Disputed, Error::::InvalidMarketStatus); ensure!(market.matches_outcome_report(&outcome), Error::::OutcomeMismatch); let report = market.report.as_ref().ok_or(Error::::MarketIsNotReported)?; @@ -249,6 +246,15 @@ mod pallet { Ok(()) } + #[inline] + fn ensure_dispute_mechanism(market: &MarketOf) -> DispatchResult { + ensure!( + market.dispute_mechanism == Some(MarketDisputeMechanism::SimpleDisputes), + Error::::MarketDoesNotHaveSimpleDisputesMechanism + ); + Ok(()) + } + fn get_auto_resolve( disputes: &[MarketDispute>], market: &MarketOf, @@ -322,10 +328,7 @@ mod pallet { _: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(market)?; let res = ResultWithWeightInfo { result: (), weight: T::WeightInfo::on_dispute_weight() }; @@ -337,10 +340,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result>, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(market)?; ensure!(market.status == MarketStatus::Disputed, Error::::InvalidMarketStatus); let disputes = Disputes::::get(market_id); @@ -370,10 +370,7 @@ mod pallet { resolved_outcome: &OutcomeReport, mut overall_imbalance: NegativeImbalanceOf, ) -> Result>, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(market)?; ensure!(market.status == MarketStatus::Disputed, Error::::InvalidMarketStatus); let disputes = Disputes::::get(market_id); @@ -427,7 +424,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> ResultWithWeightInfo> { - if market.dispute_mechanism != MarketDisputeMechanism::SimpleDisputes { + if market.dispute_mechanism != Some(MarketDisputeMechanism::SimpleDisputes) { return ResultWithWeightInfo { result: None, weight: T::WeightInfo::get_auto_resolve_weight(T::MaxDisputes::get()), @@ -448,10 +445,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(market)?; let disputes = >::get(market_id); let disputes_len = disputes.len() as u32; @@ -470,10 +464,7 @@ mod pallet { ResultWithWeightInfo>>, DispatchError, > { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(market)?; let disputes_len = >::decode_len(market_id).unwrap_or(0) as u32; @@ -496,10 +487,7 @@ mod pallet { market_id: &Self::MarketId, market: &MarketOf, ) -> Result, DispatchError> { - ensure!( - market.dispute_mechanism == MarketDisputeMechanism::SimpleDisputes, - Error::::MarketDoesNotHaveSimpleDisputesMechanism - ); + Self::ensure_dispute_mechanism(market)?; let mut disputes_len = 0u32; // `Disputes` is emtpy unless the market is disputed, so this is just a defensive @@ -553,7 +541,7 @@ where creator_fee: sp_runtime::Perbill::zero(), creator: T::PalletId::get().into_account_truncating(), market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=100), - dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), metadata: Default::default(), oracle: T::PalletId::get().into_account_truncating(), period: zeitgeist_primitives::types::MarketPeriod::Block(Default::default()), diff --git a/zrml/simple-disputes/src/tests.rs b/zrml/simple-disputes/src/tests.rs index 383792a5a..c0ad3deaf 100644 --- a/zrml/simple-disputes/src/tests.rs +++ b/zrml/simple-disputes/src/tests.rs @@ -38,7 +38,7 @@ const DEFAULT_MARKET: MarketOf = Market { creator_fee: sp_runtime::Perbill::zero(), creator: 0, market_type: MarketType::Scalar(0..=100), - dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, + dispute_mechanism: Some(MarketDisputeMechanism::SimpleDisputes), metadata: vec![], oracle: 0, period: MarketPeriod::Block(0..100), @@ -54,7 +54,7 @@ const DEFAULT_MARKET: MarketOf = Market { fn on_dispute_denies_non_simple_disputes_markets() { ExtBuilder::default().build().execute_with(|| { let mut market = DEFAULT_MARKET; - market.dispute_mechanism = MarketDisputeMechanism::Court; + market.dispute_mechanism = Some(MarketDisputeMechanism::Court); assert_noop!( SimpleDisputes::on_dispute(&0, &market), Error::::MarketDoesNotHaveSimpleDisputesMechanism @@ -66,7 +66,7 @@ fn on_dispute_denies_non_simple_disputes_markets() { fn on_resolution_denies_non_simple_disputes_markets() { ExtBuilder::default().build().execute_with(|| { let mut market = DEFAULT_MARKET; - market.dispute_mechanism = MarketDisputeMechanism::Court; + market.dispute_mechanism = Some(MarketDisputeMechanism::Court); assert_noop!( SimpleDisputes::on_resolution(&0, &market), Error::::MarketDoesNotHaveSimpleDisputesMechanism diff --git a/zrml/swaps/src/benchmarks.rs b/zrml/swaps/src/benchmarks.rs index 033a68738..cf3b942ea 100644 --- a/zrml/swaps/src/benchmarks.rs +++ b/zrml/swaps/src/benchmarks.rs @@ -130,7 +130,7 @@ fn push_default_market(caller: T::AccountId, oracle: T::AccountId) -> creator_fee: Perbill::zero(), creator: caller, market_type: MarketType::Categorical(3), - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), metadata: vec![0; 50], oracle, period: MarketPeriod::Block(0u32.into()..1u32.into()), @@ -230,7 +230,7 @@ benchmarks! { creator_fee: Perbill::zero(), creator: caller.clone(), market_type: MarketType::Categorical(category_count), - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), metadata: vec![0; 50], oracle: caller.clone(), period: MarketPeriod::Block(0u32.into()..1u32.into()), @@ -271,7 +271,7 @@ benchmarks! { creator_fee: Perbill::zero(), creator: caller.clone(), market_type: MarketType::Scalar(0..=99), - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), metadata: vec![0; 50], oracle: caller.clone(), period: MarketPeriod::Block(0u32.into()..1u32.into()), diff --git a/zrml/swaps/src/mock.rs b/zrml/swaps/src/mock.rs index 1ab5585dc..9d44b1b9f 100644 --- a/zrml/swaps/src/mock.rs +++ b/zrml/swaps/src/mock.rs @@ -335,7 +335,7 @@ pub(super) fn mock_market( creator_fee: Perbill::from_parts(0), creator: DEFAULT_MARKET_CREATOR, market_type: MarketType::Categorical(categories), - dispute_mechanism: MarketDisputeMechanism::Authorized, + dispute_mechanism: Some(MarketDisputeMechanism::Authorized), metadata: vec![0; 50], oracle: DEFAULT_MARKET_ORACLE, period: MarketPeriod::Block(0..1),