mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 03:31:05 +00:00
Add rules and unfounding to society. (#4671)
* Add rules and unfounding to society. * Docs and event * Extra bit of docs. * Cunningly reduce complexity * Remove candidates when unfounding. * Remove suspended candidates when unfounding, too.
This commit is contained in:
@@ -228,6 +228,7 @@
|
|||||||
//! * `defender_vote` - A member can vote to approve or reject a defender's continued membership
|
//! * `defender_vote` - A member can vote to approve or reject a defender's continued membership
|
||||||
//! to the society.
|
//! to the society.
|
||||||
//! * `payout` - A member can claim their first matured payment.
|
//! * `payout` - A member can claim their first matured payment.
|
||||||
|
//! * `unfound` - Allow the founder to unfound the society when they are the only member.
|
||||||
//!
|
//!
|
||||||
//! #### For Super Users
|
//! #### For Super Users
|
||||||
//!
|
//!
|
||||||
@@ -254,7 +255,7 @@ use sp_std::prelude::*;
|
|||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use sp_runtime::{Percent, ModuleId, RuntimeDebug,
|
use sp_runtime::{Percent, ModuleId, RuntimeDebug,
|
||||||
traits::{
|
traits::{
|
||||||
StaticLookup, AccountIdConversion, Saturating, Zero, IntegerSquareRoot,
|
StaticLookup, AccountIdConversion, Saturating, Zero, IntegerSquareRoot, Hash,
|
||||||
TrailingZeroInput, CheckedSub, EnsureOrigin
|
TrailingZeroInput, CheckedSub, EnsureOrigin
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -404,6 +405,10 @@ decl_storage! {
|
|||||||
pub Founder get(founder) build(|config: &GenesisConfig<T, I>| config.members.first().cloned()):
|
pub Founder get(founder) build(|config: &GenesisConfig<T, I>| config.members.first().cloned()):
|
||||||
Option<T::AccountId>;
|
Option<T::AccountId>;
|
||||||
|
|
||||||
|
/// A hash of the rules of this society concerning membership. Can only be set once and
|
||||||
|
/// only by the founder.
|
||||||
|
pub Rules get(rules): Option<T::Hash>;
|
||||||
|
|
||||||
/// The current set of candidates; bidders that are attempting to become members.
|
/// The current set of candidates; bidders that are attempting to become members.
|
||||||
pub Candidates get(candidates): Vec<Bid<T::AccountId, BalanceOf<T, I>>>;
|
pub Candidates get(candidates): Vec<Bid<T::AccountId, BalanceOf<T, I>>>;
|
||||||
|
|
||||||
@@ -805,6 +810,7 @@ decl_module! {
|
|||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - `founder` - The first member and head of the newly founded society.
|
/// - `founder` - The first member and head of the newly founded society.
|
||||||
/// - `max_members` - The initial max number of members for the society.
|
/// - `max_members` - The initial max number of members for the society.
|
||||||
|
/// - `rules` - The rules of this society concerning membership.
|
||||||
///
|
///
|
||||||
/// # <weight>
|
/// # <weight>
|
||||||
/// - Two storage mutates to set `Head` and `Founder`. O(1)
|
/// - Two storage mutates to set `Head` and `Founder`. O(1)
|
||||||
@@ -814,7 +820,7 @@ decl_module! {
|
|||||||
/// Total Complexity: O(1)
|
/// Total Complexity: O(1)
|
||||||
/// # </weight>
|
/// # </weight>
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(10_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(10_000)]
|
||||||
fn found(origin, founder: T::AccountId, max_members: u32) {
|
fn found(origin, founder: T::AccountId, max_members: u32, rules: Vec<u8>) {
|
||||||
T::FounderSetOrigin::ensure_origin(origin)?;
|
T::FounderSetOrigin::ensure_origin(origin)?;
|
||||||
ensure!(!<Head<T, I>>::exists(), Error::<T, I>::AlreadyFounded);
|
ensure!(!<Head<T, I>>::exists(), Error::<T, I>::AlreadyFounded);
|
||||||
ensure!(max_members > 1, Error::<T, I>::MaxMembers);
|
ensure!(max_members > 1, Error::<T, I>::MaxMembers);
|
||||||
@@ -823,8 +829,38 @@ decl_module! {
|
|||||||
Self::add_member(&founder)?;
|
Self::add_member(&founder)?;
|
||||||
<Head<T, I>>::put(&founder);
|
<Head<T, I>>::put(&founder);
|
||||||
<Founder<T, I>>::put(&founder);
|
<Founder<T, I>>::put(&founder);
|
||||||
|
Rules::<T, I>::put(T::Hashing::hash(&rules));
|
||||||
Self::deposit_event(RawEvent::Founded(founder));
|
Self::deposit_event(RawEvent::Founded(founder));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Anull the founding of the society.
|
||||||
|
///
|
||||||
|
/// The dispatch origin for this call must be Signed, and the signing account must be both
|
||||||
|
/// the `Founder` and the `Head`. This implies that it may only be done when there is one
|
||||||
|
/// member.
|
||||||
|
///
|
||||||
|
/// # <weight>
|
||||||
|
/// - Two storage reads O(1).
|
||||||
|
/// - Four storage removals O(1).
|
||||||
|
/// - One event.
|
||||||
|
///
|
||||||
|
/// Total Complexity: O(1)
|
||||||
|
/// # </weight>
|
||||||
|
#[weight = SimpleDispatchInfo::FixedNormal(20_000)]
|
||||||
|
fn unfound(origin) {
|
||||||
|
let founder = ensure_signed(origin)?;
|
||||||
|
ensure!(Founder::<T, I>::get() == Some(founder.clone()), Error::<T, I>::NotFounder);
|
||||||
|
ensure!(Head::<T, I>::get() == Some(founder.clone()), Error::<T, I>::NotHead);
|
||||||
|
|
||||||
|
Members::<T, I>::kill();
|
||||||
|
Head::<T, I>::kill();
|
||||||
|
Founder::<T, I>::kill();
|
||||||
|
Rules::<T, I>::kill();
|
||||||
|
Candidates::<T, I>::kill();
|
||||||
|
SuspendedCandidates::<T, I>::remove_all();
|
||||||
|
Self::deposit_event(RawEvent::Unfounded(founder));
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow suspension judgement origin to make judgement on a suspended member.
|
/// Allow suspension judgement origin to make judgement on a suspended member.
|
||||||
///
|
///
|
||||||
/// If a suspended member is forgiven, we simply add them back as a member, not affecting
|
/// If a suspended member is forgiven, we simply add them back as a member, not affecting
|
||||||
@@ -1047,6 +1083,10 @@ decl_error! {
|
|||||||
NotCandidate,
|
NotCandidate,
|
||||||
/// Too many members in the society.
|
/// Too many members in the society.
|
||||||
MaxMembers,
|
MaxMembers,
|
||||||
|
/// The caller is not the founder.
|
||||||
|
NotFounder,
|
||||||
|
/// The caller is not the head.
|
||||||
|
NotHead,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1087,6 +1127,8 @@ decl_event! {
|
|||||||
DefenderVote(AccountId, bool),
|
DefenderVote(AccountId, bool),
|
||||||
/// A new max member count has been set
|
/// A new max member count has been set
|
||||||
NewMaxMembers(u32),
|
NewMaxMembers(u32),
|
||||||
|
/// Society is unfounded.
|
||||||
|
Unfounded(AccountId),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1224,16 +1266,16 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
|
|||||||
ensure!(Self::head() != Some(m.clone()), Error::<T, I>::Head);
|
ensure!(Self::head() != Some(m.clone()), Error::<T, I>::Head);
|
||||||
ensure!(Self::founder() != Some(m.clone()), Error::<T, I>::Founder);
|
ensure!(Self::founder() != Some(m.clone()), Error::<T, I>::Founder);
|
||||||
|
|
||||||
<Members<T, I>>::mutate(|members|
|
let mut members = <Members<T, I>>::get();
|
||||||
match members.binary_search(&m) {
|
match members.binary_search(&m) {
|
||||||
Err(_) => Err(Error::<T, I>::NotMember)?,
|
Err(_) => Err(Error::<T, I>::NotMember)?,
|
||||||
Ok(i) => {
|
Ok(i) => {
|
||||||
members.remove(i);
|
members.remove(i);
|
||||||
T::MembershipChanged::change_members_sorted(&[], &[m.clone()], members);
|
T::MembershipChanged::change_members_sorted(&[], &[m.clone()], &members[..]);
|
||||||
|
<Members<T, I>>::put(members);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// End the current period and begin a new one.
|
/// End the current period and begin a new one.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use mock::*;
|
|||||||
|
|
||||||
use frame_support::{assert_ok, assert_noop};
|
use frame_support::{assert_ok, assert_noop};
|
||||||
use sp_runtime::traits::BadOrigin;
|
use sp_runtime::traits::BadOrigin;
|
||||||
|
use sp_core::blake2_256;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn founding_works() {
|
fn founding_works() {
|
||||||
@@ -31,9 +32,9 @@ fn founding_works() {
|
|||||||
assert_eq!(Society::pot(), 0);
|
assert_eq!(Society::pot(), 0);
|
||||||
// Account 1 is set as the founder origin
|
// Account 1 is set as the founder origin
|
||||||
// Account 5 cannot start a society
|
// Account 5 cannot start a society
|
||||||
assert_noop!(Society::found(Origin::signed(5), 20, 100), BadOrigin);
|
assert_noop!(Society::found(Origin::signed(5), 20, 100, vec![]), BadOrigin);
|
||||||
// Account 1 can start a society, where 10 is the founding member
|
// Account 1 can start a society, where 10 is the founding member
|
||||||
assert_ok!(Society::found(Origin::signed(1), 10, 100));
|
assert_ok!(Society::found(Origin::signed(1), 10, 100, b"be cool".to_vec()));
|
||||||
// Society members only include 10
|
// Society members only include 10
|
||||||
assert_eq!(Society::members(), vec![10]);
|
assert_eq!(Society::members(), vec![10]);
|
||||||
// 10 is the head of the society
|
// 10 is the head of the society
|
||||||
@@ -42,11 +43,39 @@ fn founding_works() {
|
|||||||
assert_eq!(Society::founder(), Some(10));
|
assert_eq!(Society::founder(), Some(10));
|
||||||
// 100 members max
|
// 100 members max
|
||||||
assert_eq!(Society::max_members(), 100);
|
assert_eq!(Society::max_members(), 100);
|
||||||
|
// rules are correct
|
||||||
|
assert_eq!(Society::rules(), Some(blake2_256(b"be cool").into()));
|
||||||
// Pot grows after first rotation period
|
// Pot grows after first rotation period
|
||||||
run_to_block(4);
|
run_to_block(4);
|
||||||
assert_eq!(Society::pot(), 1000);
|
assert_eq!(Society::pot(), 1000);
|
||||||
// Cannot start another society
|
// Cannot start another society
|
||||||
assert_noop!(Society::found(Origin::signed(1), 20, 100), Error::<Test, _>::AlreadyFounded);
|
assert_noop!(
|
||||||
|
Society::found(Origin::signed(1), 20, 100, vec![]),
|
||||||
|
Error::<Test, _>::AlreadyFounded
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unfounding_works() {
|
||||||
|
EnvBuilder::new().with_max_members(0).with_members(vec![]).execute(|| {
|
||||||
|
// Account 1 sets the founder...
|
||||||
|
assert_ok!(Society::found(Origin::signed(1), 10, 100, vec![]));
|
||||||
|
// Account 2 cannot unfound it as it's not the founder.
|
||||||
|
assert_noop!(Society::unfound(Origin::signed(2)), Error::<Test, _>::NotFounder);
|
||||||
|
// Account 10 can, though.
|
||||||
|
assert_ok!(Society::unfound(Origin::signed(10)));
|
||||||
|
|
||||||
|
// 1 sets the founder to 20 this time
|
||||||
|
assert_ok!(Society::found(Origin::signed(1), 20, 100, vec![]));
|
||||||
|
// Bring in a new member...
|
||||||
|
assert_ok!(Society::bid(Origin::signed(10), 0));
|
||||||
|
run_to_block(4);
|
||||||
|
assert_ok!(Society::vote(Origin::signed(20), 10, true));
|
||||||
|
run_to_block(8);
|
||||||
|
|
||||||
|
// Unfounding won't work now, even though it's from 20.
|
||||||
|
assert_noop!(Society::unfound(Origin::signed(20)), Error::<Test, _>::NotHead);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user