Skip to content

Commit

Permalink
Add reject_reason in MarketRejected event (#835)
Browse files Browse the repository at this point in the history
* Add reject_reason in MarketRejected event

* Fix broken weight file
  • Loading branch information
vivekvpandya authored Oct 21, 2022
1 parent 8c6395f commit 5994559
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 28 deletions.
7 changes: 7 additions & 0 deletions docs/changelog_for_devs.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# v0.3.7

- `reject_market` extrinsic now requires `reject_reason` parameter which is
`Vec<u8>`. The config constant `MaxRejectReasonLen` defines maximum length of
above parameter. `MarketRejected` event also contains `reject_reason` so that
it can be cached for market creator.

# v0.3.6

- Added new field `deadlines` in Market structure, which has `grace_period`,
Expand Down
1 change: 1 addition & 0 deletions primitives/src/constants/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ parameter_types! {
pub const MaxDisputeDuration: BlockNumber = 5;
pub const MaxGracePeriod: BlockNumber = 2;
pub const MaxOracleDuration: BlockNumber = 3;
pub const MaxRejectReasonLen: u32 = 1024;
}

// Simple disputes parameters
Expand Down
2 changes: 2 additions & 0 deletions runtime/battery-station/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ parameter_types! {
/// (Slashable) A bond for creation markets that do not require approval. Slashed in case
/// the market is forcefully destroyed.
pub const ValidityBond: Balance = 50 * CENT;
/// Maximum string length allowed for reject reason.
pub const MaxRejectReasonLen: u32 = 1024;

// Preimage
pub const PreimageMaxSize: u32 = 4096 * 1024;
Expand Down
1 change: 1 addition & 0 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,7 @@ macro_rules! impl_config_traits {
type MaxMarketPeriod = MaxMarketPeriod;
type MinCategories = MinCategories;
type MinSubsidyPeriod = MinSubsidyPeriod;
type MaxRejectReasonLen = MaxRejectReasonLen;
type OracleBond = OracleBond;
type PalletId = PmPalletId;
type RejectOrigin = EnsureRootOrHalfAdvisoryCommittee;
Expand Down
2 changes: 2 additions & 0 deletions runtime/zeitgeist/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ parameter_types! {
/// (Slashable) A bond for creation markets that do not require approval. Slashed in case
/// the market is forcefully destroyed.
pub const ValidityBond: Balance = 1_000 * BASE;
/// Maximum string length allowed for reject reason.
pub const MaxRejectReasonLen: u32 = 1024;

// Preimage
pub const PreimageMaxSize: u32 = 4096 * 1024;
Expand Down
4 changes: 3 additions & 1 deletion zrml/prediction-markets/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ benchmarks! {
reject_market {
let c in 0..63;
let o in 0..63;
let r in 0..<T as Config>::MaxRejectReasonLen::get();

let range_start: MomentOf<T> = 100_000u64.saturated_into();
let range_end: MomentOf<T> = 1_000_000u64.saturated_into();
Expand All @@ -915,7 +916,8 @@ benchmarks! {
}

let reject_origin = T::RejectOrigin::successful_origin();
let call = Call::<T>::reject_market { market_id };
let reject_reason: Vec<u8> = vec![0; r as usize];
let call = Call::<T>::reject_market { market_id, reject_reason };
}: { call.dispatch_bypass_filter(reject_origin)? }

report {
Expand Down
33 changes: 27 additions & 6 deletions zrml/prediction-markets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ mod pallet {
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::MarketId;
pub(crate) type MomentOf<T> = <<T as Config>::MarketCommons as MarketCommonsPalletApi>::Moment;
pub type CacheSize = ConstU32<64>;
pub type RejectReason<T> = BoundedVec<u8, <T as Config>::MaxRejectReasonLen>;

#[pallet::call]
impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -978,21 +979,34 @@ mod pallet {
/// and `m` is the number of market ids,
/// which close at the same time as the specified market.
#[pallet::weight((
T::WeightInfo::reject_market(CacheSize::get(), CacheSize::get()),
T::WeightInfo::reject_market(
CacheSize::get(),
CacheSize::get(),
reject_reason.len() as u32,
),
Pays::No,
))]
#[transactional]
pub fn reject_market(
origin: OriginFor<T>,
#[pallet::compact] market_id: MarketIdOf<T>,
reject_reason: Vec<u8>,
) -> DispatchResultWithPostInfo {
T::RejectOrigin::ensure_origin(origin)?;
let market = T::MarketCommons::market(&market_id)?;
let open_ids_len = Self::clear_auto_open(&market_id)?;
let close_ids_len = Self::clear_auto_close(&market_id)?;
Self::do_reject_market(&market_id, market)?;
let reject_reason: RejectReason<T> = reject_reason
.try_into()
.map_err(|_| Error::<T>::RejectReasonLengthExceedsMaxRejectReasonLen)?;
let reject_reason_len = reject_reason.len() as u32;
Self::do_reject_market(&market_id, market, reject_reason)?;
// The RejectOrigin should not pay fees for providing this service
Ok((Some(T::WeightInfo::reject_market(close_ids_len, open_ids_len)), Pays::No).into())
Ok((
Some(T::WeightInfo::reject_market(close_ids_len, open_ids_len, reject_reason_len)),
Pays::No,
)
.into())
}

/// Reports the outcome of a market.
Expand Down Expand Up @@ -1263,6 +1277,10 @@ mod pallet {
#[pallet::constant]
type MaxDisputeDuration: Get<Self::BlockNumber>;

/// The maximum length of reject reason string.
#[pallet::constant]
type MaxRejectReasonLen: Get<u32>;

//NOTE: DisputePeriod will be removed once relevant migrations are executed.
/// The number of blocks the dispute period remains open.
#[pallet::constant]
Expand Down Expand Up @@ -1361,6 +1379,8 @@ mod pallet {
NoWinningBalance,
/// Submitted outcome does not match market type.
OutcomeMismatch,
/// RejectReason's length greater than MaxRejectReasonLen.
RejectReasonLengthExceedsMaxRejectReasonLen,
/// The report is not coming from designated oracle.
ReporterNotOracle,
/// It was tried to append an item to storage beyond the boundaries.
Expand Down Expand Up @@ -1424,8 +1444,8 @@ mod pallet {
MarketDisputed(MarketIdOf<T>, MarketStatus, MarketDispute<T::AccountId, T::BlockNumber>),
/// An advised market has ended before it was approved or rejected. \[market_id\]
MarketExpired(MarketIdOf<T>),
/// A pending market has been rejected as invalid. \[market_id\]
MarketRejected(MarketIdOf<T>),
/// A pending market has been rejected as invalid with a reason. \[market_id, reject_reason\]
MarketRejected(MarketIdOf<T>, RejectReason<T>),
/// A market has been reported on \[market_id, new_market_status, reported_outcome\]
MarketReported(MarketIdOf<T>, MarketStatus, Report<T::AccountId, T::BlockNumber>),
/// A market has been resolved \[market_id, new_market_status, real_outcome\]
Expand Down Expand Up @@ -1796,6 +1816,7 @@ mod pallet {
pub(crate) fn do_reject_market(
market_id: &MarketIdOf<T>,
market: Market<T::AccountId, T::BlockNumber, MomentOf<T>>,
reject_reason: RejectReason<T>,
) -> DispatchResult {
ensure!(market.status == MarketStatus::Proposed, Error::<T>::InvalidMarketStatus);
let creator = &market.creator;
Expand All @@ -1816,7 +1837,7 @@ mod pallet {
T::OracleBond::get().saturating_add(advisory_bond_unreserve_amount),
);
T::MarketCommons::remove_market(market_id)?;
Self::deposit_event(Event::MarketRejected(*market_id));
Self::deposit_event(Event::MarketRejected(*market_id, reject_reason));
Self::deposit_event(Event::MarketDestroyed(*market_id));
Ok(())
}
Expand Down
10 changes: 6 additions & 4 deletions zrml/prediction-markets/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ use zeitgeist_primitives::{
CourtPalletId, DisputeFactor, ExistentialDeposit, ExistentialDeposits, ExitFee,
GetNativeCurrencyId, LiquidityMiningPalletId, MaxApprovals, MaxAssets, MaxCategories,
MaxDisputeDuration, MaxDisputes, MaxGracePeriod, MaxInRatio, MaxMarketPeriod,
MaxOracleDuration, MaxOutRatio, MaxReserves, MaxSubsidyPeriod, MaxSwapFee, MaxTotalWeight,
MaxWeight, MinAssets, MinCategories, MinDisputeDuration, MinLiquidity, MinOracleDuration,
MinSubsidy, MinSubsidyPeriod, MinWeight, MinimumPeriod, PmPalletId, SimpleDisputesPalletId,
StakeWeight, SwapsPalletId, TreasuryPalletId, BASE, CENT, MILLISECS_PER_BLOCK,
MaxOracleDuration, MaxOutRatio, MaxRejectReasonLen, MaxReserves, MaxSubsidyPeriod,
MaxSwapFee, MaxTotalWeight, MaxWeight, MinAssets, MinCategories, MinDisputeDuration,
MinLiquidity, MinOracleDuration, MinSubsidy, MinSubsidyPeriod, MinWeight, MinimumPeriod,
PmPalletId, SimpleDisputesPalletId, StakeWeight, SwapsPalletId, TreasuryPalletId, BASE,
CENT, MILLISECS_PER_BLOCK,
},
types::{
AccountIdTest, Amount, Asset, Balance, BasicCurrencyAdapter, BlockNumber, BlockTest,
Expand Down Expand Up @@ -125,6 +126,7 @@ impl crate::Config for Runtime {
type MaxMarketPeriod = MaxMarketPeriod;
type MinCategories = MinCategories;
type MinSubsidyPeriod = MinSubsidyPeriod;
type MaxRejectReasonLen = MaxRejectReasonLen;
type OracleBond = OracleBond;
type PalletId = PmPalletId;
type RejectOrigin = EnsureSignedBy<Sudo, AccountIdTest>;
Expand Down
48 changes: 42 additions & 6 deletions zrml/prediction-markets/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,15 +895,24 @@ fn it_allows_advisory_origin_to_approve_markets() {
#[test]
fn it_allows_the_advisory_origin_to_reject_markets() {
ExtBuilder::default().build().execute_with(|| {
run_to_block(2);
// Creates an advised market.
simple_create_categorical_market(MarketCreation::Advised, 0..1, ScoringRule::CPMM);
simple_create_categorical_market(MarketCreation::Advised, 4..6, ScoringRule::CPMM);

// make sure it's in status proposed
let market = MarketCommons::market(&0);
assert_eq!(market.unwrap().status, MarketStatus::Proposed);

let reject_reason: Vec<u8> =
vec![0; <Runtime as Config>::MaxRejectReasonLen::get() as usize];
// Now it should work from SUDO
assert_ok!(PredictionMarkets::reject_market(Origin::signed(SUDO), 0));
assert_ok!(PredictionMarkets::reject_market(
Origin::signed(SUDO),
0,
reject_reason.clone()
));
let reject_reason = reject_reason.try_into().expect("BoundedVec conversion failed");
System::assert_has_event(Event::MarketRejected(0, reject_reason).into());

assert_noop!(
MarketCommons::market(&0),
Expand All @@ -912,6 +921,25 @@ fn it_allows_the_advisory_origin_to_reject_markets() {
});
}

#[test]
fn reject_errors_if_reject_reason_is_too_long() {
ExtBuilder::default().build().execute_with(|| {
// Creates an advised market.
simple_create_categorical_market(MarketCreation::Advised, 0..1, ScoringRule::CPMM);

// make sure it's in status proposed
let market = MarketCommons::market(&0);
assert_eq!(market.unwrap().status, MarketStatus::Proposed);

let reject_reason: Vec<u8> =
vec![0; <Runtime as Config>::MaxRejectReasonLen::get() as usize + 1];
assert_noop!(
PredictionMarkets::reject_market(Origin::signed(SUDO), 0, reject_reason),
Error::<Runtime>::RejectReasonLengthExceedsMaxRejectReasonLen
);
});
}

#[test]
fn reject_market_unreserves_oracle_bond_and_slashes_advisory_bond() {
ExtBuilder::default().build().execute_with(|| {
Expand All @@ -931,7 +959,9 @@ fn reject_market_unreserves_oracle_bond_and_slashes_advisory_bond() {
let balance_reserved_before_alice =
Balances::reserved_balance_named(&PredictionMarkets::reserve_id(), &ALICE);

assert_ok!(PredictionMarkets::reject_market(Origin::signed(SUDO), 0));
let reject_reason: Vec<u8> =
vec![0; <Runtime as Config>::MaxRejectReasonLen::get() as usize];
assert_ok!(PredictionMarkets::reject_market(Origin::signed(SUDO), 0, reject_reason));

// AdvisoryBond gets slashed after reject_market
// OracleBond gets unreserved after reject_market
Expand Down Expand Up @@ -969,7 +999,9 @@ fn reject_market_clears_auto_close_blocks() {
simple_create_categorical_market(MarketCreation::Advised, 33..66, ScoringRule::CPMM);
simple_create_categorical_market(MarketCreation::Advised, 22..66, ScoringRule::CPMM);
simple_create_categorical_market(MarketCreation::Advised, 22..33, ScoringRule::CPMM);
assert_ok!(PredictionMarkets::reject_market(Origin::signed(SUDO), 0));
let reject_reason: Vec<u8> =
vec![0; <Runtime as Config>::MaxRejectReasonLen::get() as usize];
assert_ok!(PredictionMarkets::reject_market(Origin::signed(SUDO), 0, reject_reason));

let auto_close = MarketIdsPerCloseBlock::<Runtime>::get(66);
assert_eq!(auto_close.len(), 1);
Expand Down Expand Up @@ -2478,8 +2510,10 @@ fn reject_market_fails_on_permissionless_market() {
ExtBuilder::default().build().execute_with(|| {
// Creates an advised market.
simple_create_categorical_market(MarketCreation::Permissionless, 0..1, ScoringRule::CPMM);
let reject_reason: Vec<u8> =
vec![0; <Runtime as Config>::MaxRejectReasonLen::get() as usize];
assert_noop!(
PredictionMarkets::reject_market(Origin::signed(SUDO), 0),
PredictionMarkets::reject_market(Origin::signed(SUDO), 0, reject_reason),
Error::<Runtime>::InvalidMarketStatus
);
});
Expand All @@ -2491,8 +2525,10 @@ fn reject_market_fails_on_approved_market() {
// Creates an advised market.
simple_create_categorical_market(MarketCreation::Advised, 0..1, ScoringRule::CPMM);
assert_ok!(PredictionMarkets::approve_market(Origin::signed(SUDO), 0));
let reject_reason: Vec<u8> =
vec![0; <Runtime as Config>::MaxRejectReasonLen::get() as usize];
assert_noop!(
PredictionMarkets::reject_market(Origin::signed(SUDO), 0),
PredictionMarkets::reject_market(Origin::signed(SUDO), 0, reject_reason),
Error::<Runtime>::InvalidMarketStatus
);
});
Expand Down
24 changes: 13 additions & 11 deletions zrml/prediction-markets/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub trait WeightInfoZeitgeist {
fn process_subsidy_collecting_markets_raw(a: u32) -> Weight;
fn redeem_shares_categorical() -> Weight;
fn redeem_shares_scalar() -> Weight;
fn reject_market(c: u32, o: u32) -> Weight;
fn reject_market(c: u32, o: u32, r: u32) -> Weight;
fn report(m: u32) -> Weight;
fn sell_complete_set(a: u32) -> Weight;
fn start_subsidy(a: u32) -> Weight;
Expand Down Expand Up @@ -178,7 +178,7 @@ impl<T: frame_system::Config> WeightInfoZeitgeist for WeightInfo<T> {
.saturating_add((28_533_000 as Weight).saturating_mul(d as Weight))
.saturating_add(T::DbWeight::get().reads(7 as Weight))
.saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(d as Weight)))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
.saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(d as Weight)))
}
// Storage: MarketCommons Markets (r:1 w:1)
Expand All @@ -197,7 +197,7 @@ impl<T: frame_system::Config> WeightInfoZeitgeist for WeightInfo<T> {
.saturating_add((30_863_000 as Weight).saturating_mul(d as Weight))
.saturating_add(T::DbWeight::get().reads(8 as Weight))
.saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(d as Weight)))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
.saturating_add(T::DbWeight::get().writes(7 as Weight))
.saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(d as Weight)))
}
// Storage: MarketCommons Markets (r:1 w:1)
Expand Down Expand Up @@ -375,14 +375,16 @@ impl<T: frame_system::Config> WeightInfoZeitgeist for WeightInfo<T> {
// Storage: PredictionMarkets MarketIdsPerOpenTimeFrame (r:1 w:1)
// Storage: PredictionMarkets MarketIdsPerCloseTimeFrame (r:1 w:1)
// Storage: Balances Reserves (r:1 w:1)
fn reject_market(c: u32, o: u32) -> Weight {
(84_109_000 as Weight)
// Standard Error: 3_000
.saturating_add((6_000 as Weight).saturating_mul(c as Weight))
// Standard Error: 3_000
.saturating_add((32_000 as Weight).saturating_mul(o as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(4 as Weight))
fn reject_market(c: u32, o: u32, r: u32) -> Weight {
(70_584_000 as Weight)
// Standard Error: 275_000
.saturating_add((93_000 as Weight).saturating_mul(c as Weight))
// Standard Error: 275_000
.saturating_add((118_000 as Weight).saturating_mul(o as Weight))
// Standard Error: 16_000
.saturating_add((12_000 as Weight).saturating_mul(r as Weight))
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
}
// Storage: MarketCommons Markets (r:1 w:1)
// Storage: Timestamp Now (r:1 w:0)
Expand Down

0 comments on commit 5994559

Please sign in to comment.