Skip to content

Commit

Permalink
Third iteration of the Court pallet (#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
c410-f3r authored Jul 19, 2021
1 parent 081f6c6 commit eeceba3
Show file tree
Hide file tree
Showing 18 changed files with 180 additions and 76 deletions.
22 changes: 22 additions & 0 deletions primitives/src/dispute_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::types::{Market, OutcomeReport, ResolutionCounters};
use frame_support::dispatch::{DispatchError, DispatchResult};

/// Dispute Api
pub trait DisputeApi {
type AccountId;
type BlockNumber;
type MarketId;
type Origin;

/// Disputes a reported outcome.
fn on_dispute(
origin: Self::Origin,
market_id: Self::MarketId,
outcome: OutcomeReport,
) -> Result<[u32; 2], DispatchError>;

/// Manages markets resolutions moving all reported markets to resolved.
fn on_resolution<F>(now: Self::BlockNumber, cb: F) -> DispatchResult
where
F: FnMut(&Market<Self::AccountId, Self::BlockNumber>, ResolutionCounters);
}
2 changes: 2 additions & 0 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ extern crate alloc;

mod asset;
pub mod constants;
mod dispute_api;
mod market;
mod outcome_report;
mod pool;
mod pool_status;
mod resolution_counters;
mod serde_wrapper;
mod swaps;
pub mod traits;
Expand Down
File renamed without changes.
3 changes: 2 additions & 1 deletion primitives/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub use crate::{
swaps::Swaps, zeitgeist_multi_reservable_currency::ZeitgeistMultiReservableCurrency,
dispute_api::DisputeApi, swaps::Swaps,
zeitgeist_multi_reservable_currency::ZeitgeistMultiReservableCurrency,
};
2 changes: 1 addition & 1 deletion primitives/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub use crate::{
asset::*, market::*, outcome_report::OutcomeReport, pool::Pool, pool_status::PoolStatus,
serde_wrapper::*,
resolution_counters::ResolutionCounters, serde_wrapper::*,
};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Result, Unstructured};
Expand Down
2 changes: 1 addition & 1 deletion zrml/court/src/juror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::JurorStatus;
/// * Types
///
/// * `B`: Balance
#[derive(parity_scale_codec::Decode, parity_scale_codec::Encode)]
#[derive(Debug, PartialEq, parity_scale_codec::Decode, parity_scale_codec::Encode)]
pub struct Juror<B> {
pub(crate) staked: B,
pub(crate) status: JurorStatus,
Expand Down
2 changes: 1 addition & 1 deletion zrml/court/src/juror_status.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[derive(parity_scale_codec::Decode, parity_scale_codec::Encode)]
#[derive(Debug, PartialEq, parity_scale_codec::Decode, parity_scale_codec::Encode)]
pub enum JurorStatus {
Ok,
Tardy,
Expand Down
61 changes: 53 additions & 8 deletions zrml/court/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,48 @@ mod pallet {
use frame_support::{
dispatch::DispatchResult,
pallet_prelude::StorageMap,
traits::{Currency, Hooks, IsType},
traits::{Currency, Get, Hooks, IsType, ReservableCurrency},
Blake2_128Concat,
};
use frame_system::{ensure_signed, pallet_prelude::OriginFor};
use sp_runtime::DispatchError;
use sp_runtime::{traits::Saturating, ArithmeticError, DispatchError, SaturatedConversion};
use zeitgeist_primitives::{
traits::DisputeApi,
types::{Market, OutcomeReport, ResolutionCounters},
};
use zrml_market_commons::MarketCommonsPalletApi;

pub(crate) type BalanceOf<T> =
<CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
pub(crate) type CurrencyOf<T> =
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::Currency;
pub(crate) type MarketIdOf<T> =
<<T as Config>::MarketCommons as MarketCommonsPalletApi>::MarketId;

#[pallet::call]
impl<T: Config> Pallet<T> {
#[frame_support::transactional]
#[pallet::weight(0)]
pub fn exit_court(origin: OriginFor<T>) -> DispatchResult {
let account_id = ensure_signed(origin)?;
let _ = Self::juror(&account_id)?;
Jurors::<T>::remove(account_id);
let juror = Self::juror(&account_id)?;
Jurors::<T>::remove(&account_id);
CurrencyOf::<T>::unreserve(&account_id, juror.staked);
Ok(())
}

#[frame_support::transactional]
#[pallet::weight(0)]
pub fn join_court(origin: OriginFor<T>) -> DispatchResult {
let account_id = ensure_signed(origin)?;
if Jurors::<T>::get(&account_id).is_some() {
return Err(Error::<T>::JurorAlreadyExists.into());
}
Jurors::<T>::insert(
account_id,
Juror { staked: Default::default(), status: JurorStatus::Ok },
);
let jurors_num = Jurors::<T>::iter().count();
let jurors_num_plus_one = jurors_num.checked_add(1).ok_or(ArithmeticError::Overflow)?;
let stake = Self::current_required_stake(jurors_num_plus_one);
Jurors::<T>::insert(&account_id, Juror { staked: stake, status: JurorStatus::Ok });
CurrencyOf::<T>::reserve(&account_id, stake)?;
Ok(())
}
}
Expand All @@ -66,6 +76,9 @@ mod pallet {
AccountId = Self::AccountId,
BlockNumber = Self::BlockNumber,
>;

/// Weight used to calculate the necessary staking amount to become a juror
type StakeWeight: Get<BalanceOf<Self>>;
}

#[pallet::error]
Expand All @@ -91,12 +104,44 @@ mod pallet {
where
T: Config,
{
// No-one can stake more than BalanceOf::<T>::max(), therefore, this function saturates
// arithmetic operations.
fn current_required_stake(jurors_num: usize) -> BalanceOf<T> {
let jurors_len: BalanceOf<T> = jurors_num.saturated_into();
T::StakeWeight::get().saturating_mul(jurors_len)
}

// Retrieves a juror from the storage
fn juror(account_id: &T::AccountId) -> Result<Juror<BalanceOf<T>>, DispatchError> {
Jurors::<T>::get(account_id).ok_or_else(|| Error::<T>::JurorDoesNotExists.into())
}
}

impl<T> DisputeApi for Pallet<T>
where
T: Config,
{
type AccountId = T::AccountId;
type BlockNumber = T::BlockNumber;
type Origin = T::Origin;
type MarketId = MarketIdOf<T>;

fn on_dispute(
_origin: Self::Origin,
_market_id: Self::MarketId,
_outcome: OutcomeReport,
) -> Result<[u32; 2], DispatchError> {
todo!()
}

fn on_resolution<F>(_now: Self::BlockNumber, _cb: F) -> DispatchResult
where
F: FnMut(&Market<Self::AccountId, Self::BlockNumber>, ResolutionCounters),
{
todo!()
}
}

/// Accounts that stake funds to decide outcomes.
#[pallet::storage]
pub type Jurors<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, Juror<BalanceOf<T>>>;
Expand Down
7 changes: 5 additions & 2 deletions zrml/court/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ use zeitgeist_primitives::{
};

pub const ALICE: AccountIdTest = 0;
pub const BOB: AccountIdTest = 1;

type Block = BlockTest<Runtime>;
type UncheckedExtrinsic = UncheckedExtrinsicTest<Runtime>;

parameter_types! {
pub const LmPalletId: PalletId = PalletId(*b"test/lmg");
pub const BlockHashCount: u64 = BLOCK_HASH_COUNT;
pub const LmPalletId: PalletId = PalletId(*b"test/lmg");
pub const StakeWeight: u128 = 2 * BASE;
}

construct_runtime!(
Expand All @@ -40,6 +42,7 @@ construct_runtime!(

impl crate::Config for Runtime {
type Event = ();
type StakeWeight = StakeWeight;
type MarketCommons = MarketCommons;
}

Expand Down Expand Up @@ -92,7 +95,7 @@ pub struct ExtBuilder {

impl Default for ExtBuilder {
fn default() -> Self {
Self { balances: vec![(ALICE, 1_000 * BASE)] }
Self { balances: vec![(ALICE, 1_000 * BASE), (BOB, 1_000 * BASE)] }
}
}

Expand Down
41 changes: 39 additions & 2 deletions zrml/court/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
#![cfg(test)]

use crate::{
mock::{Court, ExtBuilder, Origin, Runtime, ALICE},
Error,
mock::{Balances, Court, ExtBuilder, Origin, Runtime, ALICE, BOB},
Error, Juror, JurorStatus, Jurors,
};
use frame_support::{assert_noop, assert_ok};
use zeitgeist_primitives::constants::BASE;

#[test]
fn exit_court_successfully_removes_a_juror() {
ExtBuilder::default().build().execute_with(|| {
assert_ok!(Court::join_court(Origin::signed(ALICE)));
assert_eq!(Jurors::<Runtime>::iter().count(), 1);
assert_ok!(Court::exit_court(Origin::signed(ALICE)));
assert_eq!(Jurors::<Runtime>::iter().count(), 0);
});
}

#[test]
fn exit_court_will_not_remove_an_unknown_juror() {
Expand All @@ -16,6 +27,32 @@ fn exit_court_will_not_remove_an_unknown_juror() {
});
}

#[test]
fn join_court_reserves_balance_according_to_the_number_of_jurors() {
ExtBuilder::default().build().execute_with(|| {
assert_eq!(Balances::free_balance(ALICE), 1000 * BASE);
assert_ok!(Court::join_court(Origin::signed(ALICE)));
assert_eq!(Balances::free_balance(ALICE), 998 * BASE);
assert_eq!(Balances::reserved_balance(ALICE), 2 * BASE);

assert_eq!(Balances::free_balance(BOB), 1000 * BASE);
assert_ok!(Court::join_court(Origin::signed(BOB)));
assert_eq!(Balances::free_balance(BOB), 996 * BASE);
assert_eq!(Balances::reserved_balance(BOB), 4 * BASE);
});
}

#[test]
fn join_court_successfully_stores_a_juror() {
ExtBuilder::default().build().execute_with(|| {
assert_ok!(Court::join_court(Origin::signed(ALICE)));
assert_eq!(
Jurors::<Runtime>::iter().next().unwrap(),
(ALICE, Juror { staked: 2 * BASE, status: JurorStatus::Ok })
);
});
}

#[test]
fn join_court_will_not_insert_an_already_stored_juror() {
ExtBuilder::default().build().execute_with(|| {
Expand Down
6 changes: 4 additions & 2 deletions zrml/prediction-markets/fuzz/pm_full_workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
use arbitrary::Arbitrary;
use frame_support::traits::Hooks;
use libfuzzer_sys::fuzz_target;
use zeitgeist_primitives::types::{MarketCreation, MarketEnd, MultiHash, OutcomeReport};
use zeitgeist_primitives::{
traits::DisputeApi,
types::{MarketCreation, MarketEnd, MultiHash, OutcomeReport},
};
use zrml_prediction_markets::mock::{
ExtBuilder, Origin, PredictionMarkets, SimpleDisputes, System,
};
use zrml_simple_disputes::DisputeApi;

fuzz_target!(|data: Data| {
let mut ext = ExtBuilder::default().build();
Expand Down
3 changes: 2 additions & 1 deletion zrml/prediction-markets/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ use orml_traits::MultiCurrency;
use sp_runtime::traits::SaturatedConversion;
use zeitgeist_primitives::{
constants::{MinLiquidity, MinWeight, BASE},
traits::DisputeApi,
types::{
Asset, MarketCreation, MarketEnd, MarketType, MultiHash, OutcomeReport, ScalarPosition,
},
};
use zrml_market_commons::MarketCommonsPalletApi;
use zrml_simple_disputes::DisputeApi;
use zrml_simple_disputes::SimpleDisputesPalletApi;

// Get default values for market creation. Also spawns an account with maximum
// amount of native currency
Expand Down
8 changes: 4 additions & 4 deletions zrml/prediction-markets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ mod pallet {
DispatchResult, SaturatedConversion,
};
use zeitgeist_primitives::{
traits::{Swaps, ZeitgeistMultiReservableCurrency},
traits::{DisputeApi, Swaps, ZeitgeistMultiReservableCurrency},
types::{
Asset, Market, MarketCreation, MarketEnd, MarketStatus, MarketType, MultiHash,
OutcomeReport, Report, ScalarPosition,
OutcomeReport, Report, ResolutionCounters, ScalarPosition,
},
};
use zrml_market_commons::MarketCommonsPalletApi;
use zrml_simple_disputes::{DisputeApi, ResolutionCounters};
use zrml_simple_disputes::SimpleDisputesPalletApi;

pub(crate) type BalanceOf<T> =
<CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
Expand Down Expand Up @@ -738,7 +738,7 @@ mod pallet {
>;

/// Responsable for handling disputes
type SimpleDisputes: DisputeApi<
type SimpleDisputes: SimpleDisputesPalletApi<
AccountId = Self::AccountId,
BlockNumber = Self::BlockNumber,
MarketId = MarketIdOf<Self>,
Expand Down
2 changes: 1 addition & 1 deletion zrml/prediction-markets/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub mod _0_1_2_move_storage_to_simple_disputes_and_market_commons {
};
use zeitgeist_primitives::types::{Market, MarketDispute, PoolId};
use zrml_market_commons::MarketCommonsPalletApi;
use zrml_simple_disputes::DisputeApi;
use zrml_simple_disputes::SimpleDisputesPalletApi;

const DISPUTES: &[u8] = b"Disputes";
const MARKET_COUNT: &[u8] = b"MarketCount";
Expand Down
3 changes: 2 additions & 1 deletion zrml/prediction-markets/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ use orml_traits::MultiCurrency;
use sp_runtime::traits::AccountIdConversion;
use zeitgeist_primitives::{
constants::BASE,
traits::DisputeApi,
types::{
Asset, Market, MarketCreation, MarketEnd, MarketStatus, MultiHash, OutcomeReport,
ScalarPosition,
},
};
use zrml_market_commons::MarketCommonsPalletApi;
use zrml_simple_disputes::DisputeApi;
use zrml_simple_disputes::SimpleDisputesPalletApi;

fn gen_metadata(byte: u8) -> MultiHash {
let mut metadata = [byte; 50];
Expand Down
Loading

0 comments on commit eeceba3

Please sign in to comment.