Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Extend dispatch options #375

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions pallets/communities/src/functions.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
// <<<<<<< Updated upstream
use self::types::BoundedCallOf;
use super::{origin::DecisionMethod, *};
// =======
// use crate::{
// origin::DecisionMethod,
// types::{
// AccountIdOf, BoundedCallOf, CommunityIdOf, CommunityInfo, CommunityState, ConstSizedField, MembershipIdOf,
// PalletsOriginOf, PollIndexOf, RuntimeCallFor, Tally, Vote, VoteOf, VoteWeight,
// },
// CommunityDecisionMethod, CommunityIdFor, CommunityVotes, Config, Error, HoldReason, Info, Metadata, Pallet,
// };
// >>>>>>> Stashed changes
use fc_traits_memberships::{GenericRank, Inspect, Rank};
use frame_support::{
dispatch::PostDispatchInfo,
Expand All @@ -8,14 +20,14 @@ use frame_support::{
fungible::{Mutate, MutateFreeze},
fungibles::{InspectHold, MutateHold},
tokens::Precision,
Polling,
Polling, QueryPreimage,
},
};
use sp_runtime::{
traits::{AccountIdConversion, Dispatchable},
DispatchResultWithInfo, TokenError,
};
use sp_std::{vec, vec::Vec};
use sp_std::vec::Vec;

impl<T: Config> Pallet<T> {
#[inline]
Expand Down Expand Up @@ -196,13 +208,14 @@ impl<T: Config> Pallet<T> {
Ok(())
}

pub(crate) fn do_dispatch_as_community_account(
pub(crate) fn do_dispatch_as(
community_id: &CommunityIdOf<T>,
call: RuntimeCallFor<T>,
call: BoundedCallOf<T>,
) -> DispatchResultWithInfo<PostDispatchInfo> {
let community_account = Self::community_account(community_id);
let signer = frame_system::RawOrigin::Signed(community_account);

let (call, _) = T::Preimages::realize(&call)?;
let post = call.dispatch(signer.into()).map_err(|e| e.error)?;
Ok(post)
}
Expand Down
45 changes: 15 additions & 30 deletions pallets/communities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,11 @@ pub mod pallet {
use frame_support::{
dispatch::{DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo},
pallet_prelude::*,
traits::{fungible, fungibles, EnsureOrigin, IsSubType, OriginTrait, Polling},
traits::{fungible, fungibles, EnsureOrigin, IsSubType, OriginTrait, Polling, QueryPreimage},
Blake2_128Concat, Parameter,
};
use frame_system::pallet_prelude::{ensure_signed, BlockNumberFor, OriginFor};
use sp_runtime::traits::{Dispatchable, StaticLookup};
use sp_std::prelude::Box;

const ONE: NonZeroU8 = NonZeroU8::MIN;

Expand Down Expand Up @@ -181,6 +180,9 @@ pub mod pallet {
/// Origin authorized to manage memeberships of an active community
type MemberMgmtOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::CommunityId>;

/// Origin authorized to dispatch calls as an account or origin of a community
type DispatchOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::CommunityId>;

type Polls: Polling<
Tally<Self>,
Class = CommunityIdOf<Self>,
Expand All @@ -200,6 +202,9 @@ pub mod pallet {
+ fungible::freeze::Inspect<Self::AccountId, Id = Self::RuntimeHoldReason>
+ fungible::freeze::Mutate<Self::AccountId, Id = Self::RuntimeHoldReason>;

/// Fetch calls that a Community can dispatch with its account
type Preimages: QueryPreimage<H = Self::Hashing>;

/// The overarching call type.
type RuntimeCall: Parameter
+ Dispatchable<RuntimeOrigin = RuntimeOriginFor<Self>, PostInfo = PostDispatchInfo>
Expand Down Expand Up @@ -236,7 +241,7 @@ pub mod pallet {

/// The origin of the pallet
#[pallet::origin]
pub type Origin<T> = origin::RawOrigin<T>;
pub type Origin<T> = origin::RawOrigin<CommunityIdOf<T>, MembershipIdOf<T>>;

/// A reason for the pallet communities placing a hold on funds.
#[pallet::composite_enum]
Expand Down Expand Up @@ -526,33 +531,13 @@ pub mod pallet {

/// Dispatch a callable as the community account
#[pallet::call_index(11)]
#[pallet::weight({
let di = call.get_dispatch_info();
let weight = T::WeightInfo::dispatch_as_account()
.saturating_add(T::DbWeight::get().reads_writes(1, 1))
.saturating_add(di.weight);
(weight, di.class)
})]
pub fn dispatch_as_account(origin: OriginFor<T>, call: Box<RuntimeCallFor<T>>) -> DispatchResultWithPostInfo {
let community_id = T::MemberMgmtOrigin::ensure_origin(origin)?;
Self::do_dispatch_as_community_account(&community_id, *call)
pub fn dispatch_as(
origin: OriginFor<T>,
target: DispatchTarget<CommunityIdOf<T>, MembershipIdOf<T>>,
call: BoundedCallOf<T>,
) -> DispatchResultWithPostInfo {
let community_id = T::DispatchOrigin::ensure_origin(origin)?;
Self::do_dispatch_as(&community_id, call)
}

// /// Dispatch a callable as the community account
// #[pallet::call_index(12)]
// #[pallet::weight({
// let di = call.get_dispatch_info();
// let weight = T::WeightInfo::dispatch_as_account()
// .saturating_add(T::DbWeight::get().reads_writes(1, 1))
// .saturating_add(di.weight);
// (weight, di.class)
// })]
// // #[cfg(any(test, feature = "testnet"))]
// pub fn dispatch_as_origin(origin: OriginFor<T>, call: Box<RuntimeCallFor<T>>)
// -> DispatchResultWithPostInfo { let community_id =
// T::MemberMgmtOrigin::ensure_origin(origin)?; let origin =
// crate::Origin::<T>::new(community_id); let post =
// call.dispatch(origin.into()).map_err(|e| e.error)?; Ok(post)
// }
}
}
2 changes: 2 additions & 0 deletions pallets/communities/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,12 @@ impl pallet_communities::Config for Test {
type Balances = Balances;
type MemberMgmt = Nfts;
type Polls = Referenda;
type Preimages = Preimage;

type CreateOrigin = EitherOf<RootCreatesCommunitiesForFree, AnyoneElsePays>;
type AdminOrigin = EnsureCommunity<Self>;
type MemberMgmtOrigin = EnsureCommunity<Self>;
type DispatchOrigin = EnsureCommunity<Self>;

type RuntimeCall = RuntimeCall;
type RuntimeOrigin = RuntimeOrigin;
Expand Down
51 changes: 26 additions & 25 deletions pallets/communities/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ pub struct EnsureCommunity<T>(PhantomData<T>);

impl<T> EnsureOrigin<RuntimeOriginFor<T>> for EnsureCommunity<T>
where
RuntimeOriginFor<T>: OriginTrait + Into<Result<RawOrigin<T>, RuntimeOriginFor<T>>> + From<RawOrigin<T>>,
RuntimeOriginFor<T>: OriginTrait
+ Into<Result<RawOrigin<CommunityIdOf<T>, MembershipIdOf<T>>, RuntimeOriginFor<T>>>
+ From<RawOrigin<CommunityIdOf<T>, MembershipIdOf<T>>>,
T: Config,
{
type Success = T::CommunityId;
Expand Down Expand Up @@ -95,32 +97,33 @@ where
/// Origin to represent the voice of a community or a subset of its members
/// as well as the voting preference of said group.
#[derive(TypeInfo, Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, Debug)]
pub struct RawOrigin<T: Config> {
community_id: CommunityIdOf<T>,
subset: Option<Subset<T>>,
pub struct RawOrigin<CommunityId, MembershipId> {
community_id: CommunityId,
subset: Option<Subset<MembershipId>>,
}

impl<T: Config> RawOrigin<T> {
pub const fn new(community_id: CommunityIdOf<T>) -> Self {
impl<CommunityId: Clone, MembershipId> RawOrigin<CommunityId, MembershipId> {
pub const fn new(community_id: CommunityId) -> Self {
RawOrigin {
community_id,
subset: None,
}
}

pub fn with_subset(&mut self, s: Subset<T>) {
pub fn with_subset(&mut self, s: Subset<MembershipId>) {
self.subset = Some(s);
}

pub fn id(&self) -> CommunityIdOf<T> {
self.community_id
pub fn id(&self) -> CommunityId {
self.community_id.clone()
}
}

/// Subsets of the community can also have a voice
#[derive(Clone, Debug, Decode, Encode, Eq, MaxEncodedLen, PartialEq, TypeInfo)]
pub enum Subset<T: Config> {
Member(MembershipIdOf<T>),
pub enum Subset<MembershipId> {
Named([u8; 4]),
Member(MembershipId),
Members { count: u32 },
Fraction(Permill),
AtLeastRank(GenericRank),
Expand All @@ -137,13 +140,13 @@ pub enum DecisionMethod<AssetId> {
}

#[cfg(feature = "xcm")]
impl<T> TryConvert<RuntimeOriginFor<T>, xcm::v3::MultiLocation> for RawOrigin<T>
impl<RuntimeOrigin, CommunityId, MembershipId> TryConvert<RuntimeOrigin, xcm::v3::MultiLocation>
for RawOrigin<CommunityId, MembershipId>
where
T: Config,
RuntimeOriginFor<T>: Into<Result<RawOrigin<T>, RuntimeOriginFor<T>>>,
xcm::v3::Junction: TryFrom<RawOrigin<T>>,
RuntimeOrigin: Clone + Into<Result<RawOrigin<CommunityId, MembershipId>, RuntimeOrigin>>,
xcm::v3::Junction: TryFrom<RawOrigin<CommunityId, MembershipId>>,
{
fn try_convert(o: RuntimeOriginFor<T>) -> Result<xcm::v3::MultiLocation, RuntimeOriginFor<T>> {
fn try_convert(o: RuntimeOrigin) -> Result<xcm::v3::MultiLocation, RuntimeOrigin> {
let Ok(community @ RawOrigin { .. }) = o.clone().into() else {
return Err(o);
};
Expand All @@ -153,14 +156,13 @@ where
}

#[cfg(feature = "xcm")]
impl<T> TryFrom<RawOrigin<T>> for xcm::v3::Junction
impl<C, M> TryFrom<RawOrigin<C, M>> for xcm::v3::Junction
where
T: Config,
u32: From<CommunityIdOf<T>>,
u32: From<C>,
{
type Error = ();

fn try_from(o: RawOrigin<T>) -> Result<Self, Self::Error> {
fn try_from(o: RawOrigin<C, M>) -> Result<Self, Self::Error> {
use xcm::v3::{BodyId, BodyPart, Junction::Plurality};
let part = match o.subset {
None => BodyPart::Voice,
Expand All @@ -180,10 +182,9 @@ where
}

#[cfg(feature = "xcm")]
impl<T: Config> TryFrom<xcm::v3::Junction> for RawOrigin<T>
impl<C, M> TryFrom<xcm::v3::Junction> for RawOrigin<C, M>
where
T: Config,
T::CommunityId: From<u32> + From<u64>,
C: From<u32> + From<u64> + Clone,
{
type Error = ();

Expand Down Expand Up @@ -212,10 +213,10 @@ impl<T, OuterOrigin> EnsureOrigin<OuterOrigin> for AsSignedByCommunity<T>
where
OuterOrigin: OriginTrait
+ From<frame_system::RawOrigin<T::AccountId>>
+ From<RawOrigin<T>>
+ From<RawOrigin<CommunityIdOf<T>, MembershipIdOf<T>>>
+ Clone
+ Into<Result<frame_system::RawOrigin<T::AccountId>, OuterOrigin>>
+ Into<Result<RawOrigin<T>, OuterOrigin>>,
+ Into<Result<RawOrigin<CommunityIdOf<T>, MembershipIdOf<T>>, OuterOrigin>>,
T: Config,
{
type Success = T::AccountId;
Expand Down
2 changes: 1 addition & 1 deletion pallets/communities/src/tests/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn weights() {
("vote", SubstrateWeight::<Test>::vote()),
("remove_vote", SubstrateWeight::<Test>::remove_vote()),
("unlock", SubstrateWeight::<Test>::unlock()),
("dispatch_as_account", SubstrateWeight::<Test>::dispatch_as_account()),
("dispatch_as", SubstrateWeight::<Test>::dispatch_as()),
] {
println!("{function}: {weight:?}",);
println!(
Expand Down
22 changes: 16 additions & 6 deletions pallets/communities/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::origin::DecisionMethod;
use crate::origin::{DecisionMethod, RawOrigin};
use crate::{CommunityDecisionMethod, Config};
use fc_traits_memberships::{Inspect, Rank};
use frame_support::pallet_prelude::*;
use frame_support::traits::{
fungible::{self, Inspect as FunInspect},
fungibles::{self, Inspect as FunsInspect},
Polling,
use frame_support::{
pallet_prelude::*,
traits::{
fungible::{self, Inspect as FunInspect},
fungibles::{self, Inspect as FunsInspect},
Bounded, Polling,
},
};
use sp_runtime::traits::{StaticLookup, UniqueSaturatedInto};
use sp_runtime::SaturatedConversion;
Expand All @@ -24,6 +26,7 @@ pub type PalletsOriginOf<T> =
pub type MembershipIdOf<T> = <T as Config>::MembershipId;
pub type RuntimeCallFor<T> = <T as Config>::RuntimeCall;
pub type RuntimeOriginFor<T> = <T as Config>::RuntimeOrigin;
pub type BoundedCallOf<T> = Bounded<<T as Config>::RuntimeCall, <T as frame_system::Config>::Hashing>;

#[cfg(feature = "runtime-benchmarks")]
pub type BenchmarkHelperOf<T> = <T as Config>::BenchmarkHelper;
Expand Down Expand Up @@ -138,6 +141,13 @@ pub enum LockUpdateType {
Remove,
}

/// Target within the community the management origin can impersonate
#[derive(Clone, Debug, Decode, Encode, MaxEncodedLen, PartialEq, TypeInfo)]
pub enum DispatchTarget<C, M> {
Account(Option<u8>),
Origin(RawOrigin<C, M>),
}

#[cfg(feature = "runtime-benchmarks")]
use {frame_benchmarking::BenchmarkError, frame_system::pallet_prelude::OriginFor};

Expand Down
6 changes: 3 additions & 3 deletions pallets/communities/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub trait WeightInfo {
fn vote() -> Weight;
fn remove_vote() -> Weight;
fn unlock() -> Weight;
fn dispatch_as_account() -> Weight;
fn dispatch_as() -> Weight;
}

/// Weights for pallet_communities using the Substrate node and recommended hardware.
Expand Down Expand Up @@ -254,7 +254,7 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
}
/// Storage: `Communities::Info` (r:1 w:0)
/// Proof: `Communities::Info` (`max_values`: None, `max_size`: Some(19), added: 2494, mode: `MaxEncodedLen`)
fn dispatch_as_account() -> Weight {
fn dispatch_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `115`
// Estimated: `3484`
Expand Down Expand Up @@ -472,7 +472,7 @@ impl WeightInfo for () {
}
/// Storage: `Communities::Info` (r:1 w:0)
/// Proof: `Communities::Info` (`max_values`: None, `max_size`: Some(19), added: 2494, mode: `MaxEncodedLen`)
fn dispatch_as_account() -> Weight {
fn dispatch_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `115`
// Estimated: `3484`
Expand Down
2 changes: 1 addition & 1 deletion runtime/kreivo/src/weights/pallet_communities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl<T: frame_system::Config> pallet_communities::WeightInfo for WeightInfo<T> {
}
/// Storage: `Communities::Info` (r:1 w:0)
/// Proof: `Communities::Info` (`max_values`: None, `max_size`: Some(19), added: 2494, mode: `MaxEncodedLen`)
fn dispatch_as_account() -> Weight {
fn dispatch_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `115`
// Estimated: `3484`
Expand Down