Skip to content

Commit

Permalink
change(pallet-communities): permissionless creation and administratio…
Browse files Browse the repository at this point in the history
…n of communities + set_admin_origin
  • Loading branch information
pandres95 committed Apr 17, 2024
1 parent 4569f58 commit 1c1b17a
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 35 deletions.
35 changes: 31 additions & 4 deletions pallets/communities/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ where
community_params::<T>(maybe_decision_method);

Pallet::<T>::create(origin.clone(), admin_origin_caller, community_id)?;
Pallet::<T>::set_decision_method(origin, community_id, decision_method)?;
Pallet::<T>::set_decision_method(admin_origin.clone(), community_id, decision_method)?;

Ok((community_id, admin_origin))
}
Expand Down Expand Up @@ -136,7 +136,7 @@ where
#[benchmarks(
where
T: frame_system::Config + crate::Config,
OriginFor<T>: From<Origin<T>>,
OriginFor<T>: From<Origin<T>> + From<frame_system::Origin<T>>,
RuntimeEventFor<T>: From<frame_system::Event<T>>,
MembershipIdOf<T>: From<u32>,
BlockNumberFor<T>: From<u32>
Expand All @@ -156,16 +156,43 @@ mod benchmarks {
assert_has_event::<T>(Event::CommunityCreated { id, origin }.into());
}

#[benchmark]
fn set_admin_origin() -> Result<(), BenchmarkError> {
// setup code
let (id, _, _, community_origin) = community_params::<T>(None);

let community_account = Communities::<T>::community_account(&id);
let signed_origin: <T as Config>::RuntimeOrigin = RawOrigin::Signed(community_account.clone()).into();
let signed_origin_caller: PalletsOriginOf<T> = signed_origin.into_caller();

Communities::<T>::create(RawOrigin::Root.into(), signed_origin_caller, id)?;

#[extrinsic_call]
_(RawOrigin::Signed(community_account), community_origin.clone());

// verification code
assert_eq!(CommunityIdFor::<T>::get(community_origin.clone()), Some(id));
assert_has_event::<T>(
Event::AdminOriginSet {
id,
origin: community_origin,
}
.into(),
);

Ok(())
}

#[benchmark]
fn set_decision_method() -> Result<(), BenchmarkError> {
// setup code
let (id, decision_method, _, admin_origin) = community_params::<T>(None);
Communities::<T>::create(RawOrigin::Root.into(), admin_origin, id)?;
Communities::<T>::create(RawOrigin::Root.into(), admin_origin.clone(), id)?;
CommunityDecisionMethod::<T>::set(id, decision_method);

#[extrinsic_call]
_(
RawOrigin::Root,
admin_origin,
id,
DecisionMethod::CommunityAsset(T::BenchmarkHelper::community_asset_id()),
);
Expand Down
33 changes: 26 additions & 7 deletions pallets/communities/src/functions.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
origin::DecisionMethod,
types::{
AccountIdOf, CommunityIdOf, CommunityInfo, CommunityState, MembershipIdOf, PalletsOriginOf, PollIndexOf,
RuntimeCallFor, Tally, Vote, VoteOf, VoteWeight,
AccountIdOf, CommunityIdOf, CommunityInfo, CommunityState, MembershipIdOf, NativeBalanceOf, PalletsOriginOf,
PollIndexOf, RuntimeCallFor, Tally, Vote, VoteOf, VoteWeight,
},
CommunityDecisionMethod, CommunityIdFor, CommunityVotes, Config, Error, HoldReason, Info, Pallet,
};
Expand All @@ -12,7 +12,8 @@ use frame_support::{
fail,
pallet_prelude::*,
traits::{
fungible::MutateFreeze as FunMutateFreeze, fungibles::MutateHold as FunsMutateHold, tokens::Precision, Polling,
fungible::Mutate, fungible::MutateFreeze as FunMutateFreeze, fungibles::MutateHold as FunsMutateHold,
tokens::Precision, Polling,
},
};
use sp_runtime::{
Expand All @@ -28,7 +29,7 @@ impl<T: Config> Pallet<T> {
}

pub fn community_exists(community_id: &T::CommunityId) -> bool {
Self::community(community_id).is_some()
Info::<T>::contains_key(community_id)
}

pub fn is_member(community_id: &T::CommunityId, who: &AccountIdOf<T>) -> bool {
Expand All @@ -49,13 +50,31 @@ impl<T: Config> Pallet<T> {
Info::<T>::mutate(community_id, |c| c.as_mut().map(|c| c.state = state));
}

pub fn register(
admin: &PalletsOriginOf<T>,
community_id: &CommunityIdOf<T>,
maybe_deposit: Option<(NativeBalanceOf<T>, AccountIdOf<T>, AccountIdOf<T>)>,
) -> DispatchResult {
if let Some((deposit, depositor, depositee)) = maybe_deposit {
T::Balances::transfer(
&depositor,
&depositee,
deposit,
frame_support::traits::tokens::Preservation::Preserve,
)?;
}

Self::do_register_community(admin, community_id)
}

/// Stores an initial info about the community
/// Sets the caller as the community admin, the initial community state
/// to its default value(awaiting)
pub(crate) fn do_register_community(admin: &PalletsOriginOf<T>, community_id: &T::CommunityId) -> DispatchResult {
if Self::community_exists(community_id) {
fail!(Error::<T>::CommunityAlreadyExists);
}
ensure!(
!Self::community_exists(community_id),
Error::<T>::CommunityAlreadyExists
);

CommunityIdFor::<T>::insert(admin, community_id);
Info::<T>::insert(community_id, CommunityInfo::default());
Expand Down
40 changes: 34 additions & 6 deletions pallets/communities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,13 @@ pub mod pallet {
+ membership::Manager<Self::AccountId, Group = CommunityIdOf<Self>, Membership = MembershipIdOf<Self>>
+ membership::Rank<Self::AccountId, Group = CommunityIdOf<Self>, Membership = MembershipIdOf<Self>>;

/// Origin authorized to manage the state of a community
type CommunityMgmtOrigin: EnsureOrigin<OriginFor<Self>>;
type CreateOrigin: EnsureOrigin<
OriginFor<Self>,
Success = Option<(NativeBalanceOf<Self>, AccountIdOf<Self>, AccountIdOf<Self>)>,
>;

/// Origin authorized to administer an active community
type AdminOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::CommunityId>;

/// Origin authorized to manage memeberships of an active community
type MemberMgmtOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::CommunityId>;
Expand Down Expand Up @@ -240,7 +245,6 @@ pub mod pallet {
/// specified [`ComumunityId`][`Config::CommunityId`], this means a
/// community exists.
#[pallet::storage]
#[pallet::getter(fn community)]
pub(super) type Info<T> = StorageMap<_, Blake2_128Concat, CommunityIdOf<T>, CommunityInfo>;

/// List of origins and how they map to communities
Expand Down Expand Up @@ -268,6 +272,10 @@ pub mod pallet {
id: T::CommunityId,
origin: PalletsOriginOf<T>,
},
AdminOriginSet {
id: T::CommunityId,
origin: PalletsOriginOf<T>,
},
DecisionMethodSet {
id: T::CommunityId,
},
Expand Down Expand Up @@ -337,16 +345,36 @@ pub mod pallet {
admin_origin: PalletsOriginOf<T>,
community_id: T::CommunityId,
) -> DispatchResult {
T::CommunityMgmtOrigin::ensure_origin(origin)?;
let maybe_deposit = T::CreateOrigin::ensure_origin(origin)?;

Self::do_register_community(&admin_origin, &community_id)?;
Self::register(&admin_origin, &community_id, maybe_deposit)?;
Self::deposit_event(Event::CommunityCreated {
id: community_id,
origin: admin_origin,
});
Ok(())
}

/// Creates a new community managed by the given origin
#[pallet::call_index(1)]
pub fn set_admin_origin(origin: OriginFor<T>, admin_origin: PalletsOriginOf<T>) -> DispatchResult {
let community_id = T::AdminOrigin::ensure_origin(origin.clone())?;

ensure!(
CommunityIdFor::<T>::get(origin.clone().caller()) == Some(community_id),
DispatchError::BadOrigin
);

CommunityIdFor::<T>::remove(origin.caller());
CommunityIdFor::<T>::insert(admin_origin.clone(), community_id);

Self::deposit_event(Event::AdminOriginSet {
id: community_id,
origin: admin_origin,
});
Ok(())
}

// === Memberships management ===

/// Enroll an account as a community member that receives a membership
Expand Down Expand Up @@ -426,7 +454,7 @@ pub mod pallet {
community_id: T::CommunityId,
decision_method: DecisionMethodFor<T>,
) -> DispatchResult {
T::CommunityMgmtOrigin::ensure_origin(origin)?;
T::AdminOrigin::ensure_origin(origin)?;
CommunityDecisionMethod::<T>::set(community_id, decision_method);

Self::deposit_event(Event::DecisionMethodSet { id: community_id });
Expand Down
6 changes: 4 additions & 2 deletions pallets/communities/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ parameter_types! {
pub const MembershipsManagerCollectionId: CommunityId = 0;
pub const MembershipNftAttr: &'static [u8; 10] = b"membership";
pub const TestCommunity: CommunityId = COMMUNITY;
pub const NoDepositOnRootRegistration: Option<(Balance, AccountId, AccountId)> = None;
}

type MembershipCollection = ItemOf<Nfts, MembershipsManagerCollectionId, AccountId>;
Expand Down Expand Up @@ -416,7 +417,8 @@ impl pallet_communities::Config for Test {
type MemberMgmt = Nfts;
type Polls = Referenda;

type CommunityMgmtOrigin = EnsureRoot<AccountId>;
type CreateOrigin = EnsureRootWithSuccess<AccountId, NoDepositOnRootRegistration>;
type AdminOrigin = EnsureCommunity<Self>;
type MemberMgmtOrigin = EnsureCommunity<Self>;

type RuntimeCall = RuntimeCall;
Expand Down Expand Up @@ -545,7 +547,7 @@ impl TestEnvBuilder {
Communities::create(RuntimeOrigin::root(), community_origin.caller().clone(), *community_id)
.expect("can add community");

Communities::set_decision_method(RuntimeOrigin::root(), *community_id, decision_method.clone())
Communities::set_decision_method(community_origin.clone(), *community_id, decision_method.clone())
.expect("can set decision info");

let mut members = self.members.iter().filter(|(cid, _)| cid == community_id);
Expand Down
2 changes: 1 addition & 1 deletion pallets/communities/src/tests/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ mod vote {
ext.execute_with(|| {
// For now, this community will vote membership-based
assert_ok!(Communities::set_decision_method(
RuntimeOrigin::root(),
TestEnvBuilder::create_community_origin(&COMMUNITY_C),
COMMUNITY_C,
DecisionMethod::Membership
));
Expand Down
5 changes: 1 addition & 4 deletions pallets/communities/src/tests/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ fn weights() {
// Examples: call available weight functions with various parameters (as applicable) to gauge weight usage in
// comparison to limits
("create", SubstrateWeight::<Test>::create()),
(
"set_metadata (64, 256, 63)",
SubstrateWeight::<Test>::set_metadata(64, 256, 64),
),
("set_admin_origin", SubstrateWeight::<Test>::set_admin_origin()),
("set_decision_method", SubstrateWeight::<Test>::set_decision_method()),
("add_member", SubstrateWeight::<Test>::add_member()),
("remove_member", SubstrateWeight::<Test>::remove_member()),
Expand Down
14 changes: 4 additions & 10 deletions pallets/communities/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ use core::marker::PhantomData;
/// Weight functions needed for pallet_communities.
pub trait WeightInfo {
fn create() -> Weight;
fn set_metadata(n: u32, d: u32, u: u32) -> Weight;
fn add_member() -> Weight;
fn set_admin_origin () -> Weight;
fn set_decision_method () -> Weight;
fn promote() -> Weight;
fn demote() -> Weight;
fn remove_member() -> Weight;
fn set_decision_method () -> Weight;
fn vote() -> Weight;
fn remove_vote() -> Weight;
fn unlock() -> Weight;
Expand Down Expand Up @@ -70,17 +70,14 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// The range of component `n` is `[1, 64]`.
/// The range of component `d` is `[1, 256]`.
/// The range of component `u` is `[1, 256]`.
fn set_metadata(_n: u32, d: u32, u: u32, ) -> Weight {
fn set_admin_origin() -> Weight {
// Proof Size summary in bytes:
// Measured: `75`
// Estimated: `4065`
// Minimum execution time: 23_340_000 picoseconds.
Weight::from_parts(37_081_339, 0)
.saturating_add(Weight::from_parts(0, 4065))
// Standard Error: 1_334
.saturating_add(Weight::from_parts(4_526, 0).saturating_mul(d.into()))
// Standard Error: 1_334
.saturating_add(Weight::from_parts(2_575, 0).saturating_mul(u.into()))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
Expand Down Expand Up @@ -291,17 +288,14 @@ impl WeightInfo for () {
/// The range of component `n` is `[1, 64]`.
/// The range of component `d` is `[1, 256]`.
/// The range of component `u` is `[1, 256]`.
fn set_metadata(_n: u32, d: u32, u: u32, ) -> Weight {
fn set_admin_origin() -> Weight {
// Proof Size summary in bytes:
// Measured: `75`
// Estimated: `4065`
// Minimum execution time: 23_340_000 picoseconds.
Weight::from_parts(37_081_339, 0)
.saturating_add(Weight::from_parts(0, 4065))
// Standard Error: 1_334
.saturating_add(Weight::from_parts(4_526, 0).saturating_mul(d.into()))
// Standard Error: 1_334
.saturating_add(Weight::from_parts(2_575, 0).saturating_mul(u.into()))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
Expand Down
3 changes: 2 additions & 1 deletion runtime/kreivo/src/communities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ where
impl pallet_communities::Config for Runtime {
type CommunityId = CommunityId;

type CommunityMgmtOrigin = EnsureRoot<AccountId>;
type CreateOrigin = EnsureRoot<AccountId>;
type AdminOrigin = EitherOf<EnsureCommunity<Self>, EnsureCommunityAccountId<Self>>;
type MemberMgmtOrigin = EitherOf<EnsureCommunity<Self>, EnsureCommunityAccountId<Self>>;
type MemberMgmt = CommunityMemberships;
type MembershipId = MembershipId;
Expand Down

0 comments on commit 1c1b17a

Please sign in to comment.