diff --git a/pallets/communities/src/benchmarking.rs b/pallets/communities/src/benchmarking.rs index 9efd44c2..2866da97 100644 --- a/pallets/communities/src/benchmarking.rs +++ b/pallets/communities/src/benchmarking.rs @@ -6,7 +6,7 @@ use self::{ origin::DecisionMethod, types::{ AccountIdOf, CommunityIdOf, DecisionMethodFor, MembershipIdOf, NativeBalanceOf, PalletsOriginOf, PollIndexOf, - Vote, + RuntimeCallFor, Vote, }, Event, HoldReason, Pallet as Communities, }; @@ -20,10 +20,10 @@ use frame_support::{ BoundedVec, }; use frame_system::{ - pallet_prelude::{BlockNumberFor, OriginFor, RuntimeCallFor}, + pallet_prelude::{BlockNumberFor, OriginFor}, RawOrigin, }; -use sp_runtime::traits::StaticLookup; +use sp_runtime::traits::{Hash, StaticLookup}; use sp_std::{vec, vec::Vec}; fn assert_has_event(generic_event: ::RuntimeEvent) { @@ -136,7 +136,7 @@ where #[benchmarks( where T: frame_system::Config + crate::Config, - RuntimeCallFor: From>, + ::RuntimeEvent: From>, MembershipIdOf: From, BlockNumberFor: From )] @@ -407,6 +407,27 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn dispatch_as_account() -> Result<(), BenchmarkError> { + // setup code + let (id, origin) = create_community::(RawOrigin::Root.into(), Some(DecisionMethod::NativeToken))?; + let remark = b"Hello, world".to_vec(); + + #[extrinsic_call] + _( + origin.into_caller(), + Box::new(frame_system::Call::::remark_with_event { remark: remark.clone() }.into()), + ); + + // verification code + let sender = Communities::::community_account(&id); + let hash = ::Hashing::hash(&remark); + + assert_has_event::(frame_system::Event::::Remarked { sender, hash }.into()); + + Ok(()) + } + impl_benchmark_test_suite!( Communities, sp_io::TestExternalities::new(Default::default()), diff --git a/pallets/communities/src/functions.rs b/pallets/communities/src/functions.rs index b0e59162..3f29bbb5 100644 --- a/pallets/communities/src/functions.rs +++ b/pallets/communities/src/functions.rs @@ -2,19 +2,23 @@ use crate::{ origin::DecisionMethod, types::{ AccountIdOf, CommunityIdOf, CommunityInfo, CommunityState, ConstSizedField, MembershipIdOf, PalletsOriginOf, - PollIndexOf, Tally, Vote, VoteOf, VoteWeight, + PollIndexOf, RuntimeCallFor, Tally, Vote, VoteOf, VoteWeight, }, CommunityDecisionMethod, CommunityIdFor, CommunityVotes, Config, Error, HoldReason, Info, Metadata, Pallet, }; use fc_traits_memberships::{GenericRank, Inspect, Rank}; use frame_support::{ + dispatch::PostDispatchInfo, fail, pallet_prelude::*, traits::{ fungible::MutateFreeze as FunMutateFreeze, fungibles::MutateHold as FunsMutateHold, tokens::Precision, Polling, }, }; -use sp_runtime::{traits::AccountIdConversion, TokenError}; +use sp_runtime::{ + traits::{AccountIdConversion, Dispatchable}, + DispatchResultWithInfo, TokenError, +}; use sp_std::vec::Vec; impl Pallet { @@ -189,6 +193,17 @@ impl Pallet { _ => Err(Error::::NoLocksInPlace.into()), } } + + pub(crate) fn do_dispatch_as_community_account( + community_id: &CommunityIdOf, + call: RuntimeCallFor, + ) -> DispatchResultWithInfo { + let community_account = Self::community_account(community_id); + let signer = frame_system::RawOrigin::Signed(community_account); + + let post = call.dispatch(signer.into()).map_err(|e| e.error)?; + Ok(post) + } } impl Tally { diff --git a/pallets/communities/src/lib.rs b/pallets/communities/src/lib.rs index 9bcffe3e..e32747f4 100644 --- a/pallets/communities/src/lib.rs +++ b/pallets/communities/src/lib.rs @@ -140,13 +140,14 @@ pub mod pallet { use core::num::NonZeroU8; use fc_traits_memberships::{self as membership, Inspect, Manager, Rank}; use frame_support::{ + dispatch::{DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo}, pallet_prelude::*, - traits::{fungible, fungibles, EnsureOrigin, Polling}, + traits::{fungible, fungibles, EnsureOrigin, IsSubType, Polling}, Blake2_128Concat, Parameter, }; use frame_system::pallet_prelude::{OriginFor, *}; - use sp_runtime::traits::StaticLookup; - use types::{PollIndexOf, *}; + use sp_runtime::traits::{Dispatchable, StaticLookup}; + use types::{PollIndexOf, RuntimeCallFor, *}; const ONE: NonZeroU8 = NonZeroU8::MIN; #[pallet::pallet] @@ -192,6 +193,15 @@ pub mod pallet { + fungible::freeze::Inspect + fungible::freeze::Mutate; + /// The overarching call type. + type RuntimeCall: Parameter + + Dispatchable + + GetDispatchInfo + + From> + + From> + + IsSubType> + + IsType<::RuntimeCall>; + /// The overarching hold reason. type RuntimeHoldReason: From; @@ -499,5 +509,19 @@ pub mod pallet { Self::do_unlock_for_vote(&who, &poll_index, &vote) } + + /// 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, call: Box>) -> DispatchResultWithPostInfo { + let community_id = T::MemberMgmtOrigin::ensure_origin(origin)?; + Self::do_dispatch_as_community_account(&community_id, *call) + } } } diff --git a/pallets/communities/src/mock.rs b/pallets/communities/src/mock.rs index f616a86a..700e5834 100644 --- a/pallets/communities/src/mock.rs +++ b/pallets/communities/src/mock.rs @@ -426,6 +426,7 @@ impl pallet_communities::Config for Test { type CommunityMgmtOrigin = EnsureRoot; type MemberMgmtOrigin = EnsureCommunity; + type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; type RuntimeHoldReason = RuntimeHoldReason; type WeightInfo = WeightInfo; diff --git a/pallets/communities/src/types.rs b/pallets/communities/src/types.rs index f0411384..d6221c9c 100644 --- a/pallets/communities/src/types.rs +++ b/pallets/communities/src/types.rs @@ -22,6 +22,7 @@ pub type AccountIdLookupOf = <::Lookup as StaticLo pub type PalletsOriginOf = <::RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; pub type MembershipIdOf = ::MembershipId; +pub type RuntimeCallFor = ::RuntimeCall; pub type SizedField = BoundedVec; pub type ConstSizedField = SizedField>; @@ -148,10 +149,7 @@ impl Tally { } #[cfg(feature = "runtime-benchmarks")] -use { - frame_benchmarking::BenchmarkError, - frame_system::pallet_prelude::{OriginFor, RuntimeCallFor}, -}; +use {frame_benchmarking::BenchmarkError, frame_system::pallet_prelude::OriginFor}; #[cfg(feature = "runtime-benchmarks")] pub trait BenchmarkHelper { diff --git a/pallets/communities/src/weights.rs b/pallets/communities/src/weights.rs index d2fbfec5..2f27d964 100644 --- a/pallets/communities/src/weights.rs +++ b/pallets/communities/src/weights.rs @@ -44,6 +44,7 @@ pub trait WeightInfo { fn vote() -> Weight; fn remove_vote() -> Weight; fn unlock() -> Weight; + fn dispatch_as_account() -> Weight; } /// Weights for pallet_communities using the Substrate node and recommended hardware. @@ -265,6 +266,14 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } + fn dispatch_as_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1079` + // Estimated: `9147` + // Minimum execution time: 128_764_000 picoseconds. + Weight::from_parts(37_944_303, 0) + .saturating_add(Weight::from_parts(0, 4065)) + } } // For backwards compatibility and tests @@ -485,4 +494,22 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().writes(3)) } + /// Storage: `CommunityReferenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `CommunityReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) + /// Storage: `Communities::CommunityVotes` (r:1 w:1) + /// Proof: `Communities::CommunityVotes` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:1) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(5682), added: 8157, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + fn dispatch_as_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1079` + // Estimated: `9147` + // Minimum execution time: 128_764_000 picoseconds. + Weight::from_parts(37_944_303, 0) + .saturating_add(Weight::from_parts(0, 4065)) + } } diff --git a/runtime/kreivo/src/communities/mod.rs b/runtime/kreivo/src/communities/mod.rs index 3f60c0d2..be4d0693 100644 --- a/runtime/kreivo/src/communities/mod.rs +++ b/runtime/kreivo/src/communities/mod.rs @@ -76,6 +76,8 @@ impl pallet_communities::Config for Runtime { type Assets = Assets; type Balances = Balances; + + type RuntimeCall = RuntimeCall; type RuntimeHoldReason = RuntimeHoldReason; type RuntimeEvent = RuntimeEvent; type WeightInfo = crate::weights::pallet_communities::WeightInfo;