Several tweaks needed for Governance 2.0 (#11124)

* Add stepped curve for referenda

* Treasury SpendOrigin

* Add tests

* Better Origin Or-gating

* Reciprocal curve

* Tests for reciprical and rounding in PerThings

* Tweaks and new quad curve

* Const derivation of reciprocal curve parameters

* Remove some unneeded code

* Actually useful linear curve

* Fixes

* Provisional curves

* Rejig 'turnout' as 'support'

* Use TypedGet

* Fixes

* Enable curve's ceil to be configured

* Formatting

* Fixes

* Fixes

* Fixes

* Remove EnsureOneOf

* Fixes

* Fixes

* Fixes

* Formatting

* Fixes

* Update frame/support/src/traits/dispatch.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Grumbles

* Formatting

* Fixes

* APIs of VoteTally should include class

* Fixes

* Fix overlay prefix removal result

* Second part of the overlay prefix removal fix.

* Formatting

* Fixes

* Add some tests and make clear rounding algo

* Fixes

* Formatting

* Revert questionable fix

* Introduce test for kill_prefix

* Fixes

* Formatting

* Fixes

* Fix possible overflow

* Docs

* Add benchmark test

* Formatting

* Update frame/referenda/src/types.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Docs

* Fixes

* Use latest API in tests

* Formatting

* Whitespace

* Use latest API in tests

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Gavin Wood
2022-05-31 11:12:34 +01:00
committed by GitHub
parent c808340d9a
commit 7808b0c349
34 changed files with 2050 additions and 339 deletions
+84 -15
View File
@@ -350,6 +350,13 @@ macro_rules! parameter_types {
I::from(Self::get())
}
}
impl $crate::traits::TypedGet for $name {
type Type = $type;
fn get() -> $type {
Self::get()
}
}
};
(IMPL $name:ident, $type:ty, $value:expr) => {
impl $name {
@@ -364,6 +371,13 @@ macro_rules! parameter_types {
I::from(Self::get())
}
}
impl $crate::traits::TypedGet for $name {
type Type = $type;
fn get() -> $type {
Self::get()
}
}
};
(IMPL_STORAGE $name:ident, $type:ty, $value:expr) => {
impl $name {
@@ -397,6 +411,13 @@ macro_rules! parameter_types {
I::from(Self::get())
}
}
impl $crate::traits::TypedGet for $name {
type Type = $type;
fn get() -> $type {
Self::get()
}
}
};
(
$( #[ $attr:meta ] )*
@@ -805,7 +826,7 @@ pub mod tests {
};
use codec::{Codec, EncodeLike};
use frame_support::traits::CrateVersion;
use sp_io::TestExternalities;
use sp_io::{MultiRemovalResults, TestExternalities};
use sp_std::result;
/// A PalletInfo implementation which just panics.
@@ -1066,15 +1087,16 @@ pub mod tests {
}
#[test]
fn double_map_basic_insert_remove_remove_prefix_should_work() {
new_test_ext().execute_with(|| {
type DoubleMap = DataDM;
fn double_map_basic_insert_remove_remove_prefix_with_commit_should_work() {
let key1 = 17u32;
let key2 = 18u32;
type DoubleMap = DataDM;
let mut e = new_test_ext();
e.execute_with(|| {
// initialized during genesis
assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64);
// get / insert / take
let key1 = 17u32;
let key2 = 18u32;
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(&key1, &key2, &4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 4u64);
@@ -1082,9 +1104,7 @@ pub mod tests {
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
// mutate
DoubleMap::mutate(&key1, &key2, |val| {
*val = 15;
});
DoubleMap::mutate(&key1, &key2, |val| *val = 15);
assert_eq!(DoubleMap::get(&key1, &key2), 15u64);
// remove
@@ -1096,13 +1116,62 @@ pub mod tests {
DoubleMap::insert(&key1, &(key2 + 1), &4u64);
DoubleMap::insert(&(key1 + 1), &key2, &4u64);
DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64);
});
e.commit_all().unwrap();
e.execute_with(|| {
assert!(matches!(
DoubleMap::clear_prefix(&key1, u32::max_value(), None),
// Note this is the incorrect answer (for now), since we are using v2 of
// `clear_prefix`.
// When we switch to v3, then this will become:
// sp_io::MultiRemovalResults::NoneLeft { db: 0, total: 2 },
sp_io::MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 },
MultiRemovalResults { maybe_cursor: None, backend: 2, unique: 2, loops: 2 }
));
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64);
assert_eq!(DoubleMap::get(&(key1 + 1), &key2), 4u64);
assert_eq!(DoubleMap::get(&(key1 + 1), &(key2 + 1)), 4u64);
});
}
#[test]
fn double_map_basic_insert_remove_remove_prefix_should_work() {
new_test_ext().execute_with(|| {
let key1 = 17u32;
let key2 = 18u32;
type DoubleMap = DataDM;
// initialized during genesis
assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64);
// get / insert / take
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(&key1, &key2, &4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 4u64);
assert_eq!(DoubleMap::take(&key1, &key2), 4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
// mutate
DoubleMap::mutate(&key1, &key2, |val| *val = 15);
assert_eq!(DoubleMap::get(&key1, &key2), 15u64);
// remove
DoubleMap::remove(&key1, &key2);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
// remove prefix
DoubleMap::insert(&key1, &key2, &4u64);
DoubleMap::insert(&key1, &(key2 + 1), &4u64);
DoubleMap::insert(&(key1 + 1), &key2, &4u64);
DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64);
// all in overlay
assert!(matches!(
DoubleMap::clear_prefix(&key1, u32::max_value(), None),
MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 }
));
// Note this is the incorrect answer (for now), since we are using v2 of
// `clear_prefix`.
// When we switch to v3, then this will become:
// MultiRemovalResults:: { maybe_cursor: None, backend: 0, unique: 2, loops: 2 },
assert!(matches!(
DoubleMap::clear_prefix(&key1, u32::max_value(), None),
MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 }
));
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64);
@@ -1321,7 +1390,7 @@ pub mod pallet_prelude {
},
traits::{
ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType,
PalletInfoAccess, StorageInfoTrait, StorageVersion,
PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet,
},
weights::{DispatchClass, Pays, Weight},
Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity,
+5 -3
View File
@@ -59,7 +59,7 @@ pub use misc::{
ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly,
EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime,
IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider,
PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, UnixTime,
PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime,
WrapperKeepOpaque, WrapperOpaque,
};
#[doc(hidden)]
@@ -93,9 +93,11 @@ pub use storage::{
};
mod dispatch;
#[allow(deprecated)]
pub use dispatch::EnsureOneOf;
pub use dispatch::{
AsEnsureOriginWithArg, DispatchableWithStorageLayer, EnsureOneOf, EnsureOrigin,
EnsureOriginWithArg, OriginTrait, UnfilteredDispatchable,
AsEnsureOriginWithArg, DispatchableWithStorageLayer, EitherOf, EitherOfDiverse, EnsureOrigin,
EnsureOriginWithArg, NeverEnsureOrigin, OriginTrait, UnfilteredDispatchable,
};
mod voting;
+103 -15
View File
@@ -43,6 +43,19 @@ pub trait EnsureOrigin<OuterOrigin> {
fn successful_origin() -> OuterOrigin;
}
/// `EnsureOrigin` implementation that always fails.
pub struct NeverEnsureOrigin<Success>(sp_std::marker::PhantomData<Success>);
impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
type Success = Success;
fn try_origin(o: OO) -> Result<Success, OO> {
Err(o)
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OO {
panic!("No `successful_origin` possible for `NeverEnsureOrigin`")
}
}
/// Some sort of check on the origin is performed by this object.
pub trait EnsureOriginWithArg<OuterOrigin, Argument> {
/// A return type.
@@ -163,13 +176,16 @@ pub trait OriginTrait: Sized {
fn signed(by: Self::AccountId) -> Self;
}
/// The "OR gate" implementation of `EnsureOrigin`.
/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
/// and `R`, with them combined using an `Either` type.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
pub struct EnsureOneOf<L, R>(sp_std::marker::PhantomData<(L, R)>);
///
/// Successful origin is derived from the left side.
pub struct EitherOfDiverse<L, R>(sp_std::marker::PhantomData<(L, R)>);
impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
EnsureOrigin<OuterOrigin> for EnsureOneOf<L, R>
EnsureOrigin<OuterOrigin> for EitherOfDiverse<L, R>
{
type Success = Either<L::Success, R::Success>;
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
@@ -183,17 +199,53 @@ impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
}
}
/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
/// and `R`, with them combined using an `Either` type.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
#[deprecated = "Use `EitherOfDiverse` instead"]
pub type EnsureOneOf<L, R> = EitherOfDiverse<L, R>;
/// "OR gate" implementation of `EnsureOrigin`, `Success` type for both `L` and `R` must
/// be equal.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
pub struct EitherOf<L, R>(sp_std::marker::PhantomData<(L, R)>);
impl<
OuterOrigin,
L: EnsureOrigin<OuterOrigin>,
R: EnsureOrigin<OuterOrigin, Success = L::Success>,
> EnsureOrigin<OuterOrigin> for EitherOf<L, R>
{
type Success = L::Success;
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
L::try_origin(o).or_else(|o| R::try_origin(o))
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OuterOrigin {
L::successful_origin()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::{ConstBool, ConstU8, TypedGet};
use std::marker::PhantomData;
struct EnsureSuccess;
struct EnsureFail;
struct EnsureSuccess<V>(PhantomData<V>);
struct EnsureFail<T>(PhantomData<T>);
impl EnsureOrigin<()> for EnsureSuccess {
type Success = ();
impl<V: TypedGet> EnsureOrigin<()> for EnsureSuccess<V> {
type Success = V::Type;
fn try_origin(_: ()) -> Result<Self::Success, ()> {
Ok(())
Ok(V::get())
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> () {
@@ -201,8 +253,8 @@ mod tests {
}
}
impl EnsureOrigin<()> for EnsureFail {
type Success = ();
impl<T> EnsureOrigin<()> for EnsureFail<T> {
type Success = T;
fn try_origin(_: ()) -> Result<Self::Success, ()> {
Err(())
}
@@ -213,10 +265,46 @@ mod tests {
}
#[test]
fn ensure_one_of_test() {
assert!(<EnsureOneOf<EnsureSuccess, EnsureSuccess>>::try_origin(()).is_ok());
assert!(<EnsureOneOf<EnsureSuccess, EnsureFail>>::try_origin(()).is_ok());
assert!(<EnsureOneOf<EnsureFail, EnsureSuccess>>::try_origin(()).is_ok());
assert!(<EnsureOneOf<EnsureFail, EnsureFail>>::try_origin(()).is_err());
fn either_of_diverse_works() {
assert_eq!(
EitherOfDiverse::<
EnsureSuccess<ConstBool<true>>,
EnsureSuccess<ConstU8<0>>,
>::try_origin(()).unwrap().left(),
Some(true)
);
assert_eq!(
EitherOfDiverse::<EnsureSuccess<ConstBool<true>>, EnsureFail<u8>>::try_origin(())
.unwrap()
.left(),
Some(true)
);
assert_eq!(
EitherOfDiverse::<EnsureFail<bool>, EnsureSuccess<ConstU8<0>>>::try_origin(())
.unwrap()
.right(),
Some(0u8)
);
assert!(EitherOfDiverse::<EnsureFail<bool>, EnsureFail<u8>>::try_origin(()).is_err());
}
#[test]
fn either_of_works() {
assert_eq!(
EitherOf::<
EnsureSuccess<ConstBool<true>>,
EnsureSuccess<ConstBool<false>>,
>::try_origin(()).unwrap(),
true
);
assert_eq!(
EitherOf::<EnsureSuccess<ConstBool<true>>, EnsureFail<bool>>::try_origin(()).unwrap(),
true
);
assert_eq!(
EitherOf::<EnsureFail<bool>, EnsureSuccess<ConstBool<false>>>::try_origin(()).unwrap(),
false
);
assert!(EitherOf::<EnsureFail<bool>, EnsureFail<bool>>::try_origin(()).is_err());
}
}
@@ -387,6 +387,16 @@ where
}
}
/// A trait for querying a single value from a type defined in the trait.
///
/// It is not required that the value is constant.
pub trait TypedGet {
/// The type which is returned.
type Type;
/// Return the current value.
fn get() -> Self::Type;
}
/// A trait for querying a single value from a type.
///
/// It is not required that the value is constant.
@@ -423,6 +433,12 @@ macro_rules! impl_const_get {
Some(T)
}
}
impl<const T: $t> TypedGet for $name<T> {
type Type = $t;
fn get() -> $t {
T
}
}
};
}
+9 -7
View File
@@ -95,16 +95,18 @@ impl<B: UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128>> CurrencyToVote<B>
}
}
pub trait VoteTally<Votes> {
fn ayes(&self) -> Votes;
fn turnout(&self) -> Perbill;
fn approval(&self) -> Perbill;
pub trait VoteTally<Votes, Class> {
fn new(_: Class) -> Self;
fn ayes(&self, class: Class) -> Votes;
fn support(&self, class: Class) -> Perbill;
fn approval(&self, class: Class) -> Perbill;
#[cfg(feature = "runtime-benchmarks")]
fn unanimity() -> Self;
fn unanimity(class: Class) -> Self;
#[cfg(feature = "runtime-benchmarks")]
fn from_requirements(turnout: Perbill, approval: Perbill) -> Self;
fn rejection(class: Class) -> Self;
#[cfg(feature = "runtime-benchmarks")]
fn from_requirements(support: Perbill, approval: Perbill, class: Class) -> Self;
}
pub enum PollStatus<Tally, Moment, Class> {
None,
Ongoing(Tally, Class),