diff --git a/substrate/frame/collective/src/lib.rs b/substrate/frame/collective/src/lib.rs index f904b42af028d54a03d0267144fdb31051fef3d4..fc4ab0c4f1bbd5f50bf08e0b45109bdf36a835e7 100644 --- a/substrate/frame/collective/src/lib.rs +++ b/substrate/frame/collective/src/lib.rs @@ -53,9 +53,10 @@ use frame_support::{ DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo, }, - ensure, + ensure, impl_ensure_origin_with_arg_ignoring_arg, traits::{ - Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, + Backing, ChangeMembers, EnsureOrigin, EnsureOriginWithArg, Get, GetBacking, + InitializeMembers, StorageVersion, }, weights::Weight, }; @@ -1154,6 +1155,12 @@ impl< } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., I: 'static, AccountId: Decode, T } > + EnsureOriginWithArg<O, T> for EnsureMember<AccountId, I> + {} +} + pub struct EnsureMembers<AccountId, I: 'static, const N: u32>(PhantomData<(AccountId, I)>); impl< O: Into<Result<RawOrigin<AccountId, I>, O>> + From<RawOrigin<AccountId, I>>, @@ -1176,6 +1183,12 @@ impl< } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., I: 'static, const N: u32, AccountId, T } > + EnsureOriginWithArg<O, T> for EnsureMembers<AccountId, I, N> + {} +} + pub struct EnsureProportionMoreThan<AccountId, I: 'static, const N: u32, const D: u32>( PhantomData<(AccountId, I)>, ); @@ -1201,6 +1214,12 @@ impl< } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., I: 'static, const N: u32, const D: u32, AccountId, T } > + EnsureOriginWithArg<O, T> for EnsureProportionMoreThan<AccountId, I, N, D> + {} +} + pub struct EnsureProportionAtLeast<AccountId, I: 'static, const N: u32, const D: u32>( PhantomData<(AccountId, I)>, ); @@ -1225,3 +1244,9 @@ impl< Ok(O::from(RawOrigin::Members(0u32, 0u32))) } } + +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., I: 'static, const N: u32, const D: u32, AccountId, T } > + EnsureOriginWithArg<O, T> for EnsureProportionAtLeast<AccountId, I, N, D> + {} +} diff --git a/substrate/frame/core-fellowship/src/lib.rs b/substrate/frame/core-fellowship/src/lib.rs index 9ca13db1726382cd90316348133f8558f6f3c1df..ba02627ec11b9213afb81972e5a5478c9c807c8c 100644 --- a/substrate/frame/core-fellowship/src/lib.rs +++ b/substrate/frame/core-fellowship/src/lib.rs @@ -65,8 +65,10 @@ use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ dispatch::DispatchResultWithPostInfo, - ensure, - traits::{tokens::Balance as BalanceTrait, EnsureOrigin, Get, RankedMembers}, + ensure, impl_ensure_origin_with_arg_ignoring_arg, + traits::{ + tokens::Balance as BalanceTrait, EnsureOrigin, EnsureOriginWithArg, Get, RankedMembers, + }, BoundedVec, RuntimeDebug, }; @@ -570,7 +572,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi type Success = T::AccountId; fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> { - let who = frame_system::EnsureSigned::try_origin(o)?; + let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?; match T::Members::rank_of(&who) { Some(rank) if rank >= MIN_RANK && Member::<T, I>::contains_key(&who) => Ok(who), _ => Err(frame_system::RawOrigin::Signed(who).into()), @@ -591,3 +593,9 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi Ok(frame_system::RawOrigin::Signed(who).into()) } } + +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { T: Config<I>, I: 'static, const MIN_RANK: u16, A } > + EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureInducted<T, I, MIN_RANK> + {} +} diff --git a/substrate/frame/ranked-collective/src/lib.rs b/substrate/frame/ranked-collective/src/lib.rs index 6296403d2a1ce04ce6239b8574165f85b0383718..6fe9fc221a7df3cd04036dc7d4270014e2047d85 100644 --- a/substrate/frame/ranked-collective/src/lib.rs +++ b/substrate/frame/ranked-collective/src/lib.rs @@ -53,8 +53,8 @@ use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, dispatch::{DispatchError, DispatchResultWithPostInfo, PostDispatchInfo}, - ensure, - traits::{EnsureOrigin, PollStatus, Polling, RankedMembers, VoteTally}, + ensure, impl_ensure_origin_with_arg_ignoring_arg, + traits::{EnsureOrigin, EnsureOriginWithArg, PollStatus, Polling, RankedMembers, VoteTally}, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -263,7 +263,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi type Success = Rank; fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> { - let who = frame_system::EnsureSigned::try_origin(o)?; + let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?; match Members::<T, I>::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(rank), _ => Err(frame_system::RawOrigin::Signed(who).into()), @@ -272,7 +272,36 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi #[cfg(feature = "runtime-benchmarks")] fn try_successful_origin() -> Result<T::RuntimeOrigin, ()> { - EnsureRankedMember::<T, I, MIN_RANK>::try_successful_origin() + <EnsureRankedMember<T, I, MIN_RANK> as EnsureOrigin<_>>::try_successful_origin() + } +} + +impl_ensure_origin_with_arg_ignoring_arg! { + impl<{ T: Config<I>, I: 'static, const MIN_RANK: u16, A }> + EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureRanked<T, I, MIN_RANK> + {} +} + +/// Guard to ensure that the given origin is a member of the collective. The rank of the member is +/// the `Success` value. +pub struct EnsureOfRank<T, I>(PhantomData<(T, I)>); +impl<T: Config<I>, I: 'static> EnsureOriginWithArg<T::RuntimeOrigin, Rank> for EnsureOfRank<T, I> { + type Success = (T::AccountId, Rank); + + fn try_origin(o: T::RuntimeOrigin, min_rank: &Rank) -> Result<Self::Success, T::RuntimeOrigin> { + let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?; + match Members::<T, I>::get(&who) { + Some(MemberRecord { rank, .. }) if rank >= *min_rank => Ok((who, rank)), + _ => Err(frame_system::RawOrigin::Signed(who).into()), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(min_rank: &Rank) -> Result<T::RuntimeOrigin, ()> { + let who = frame_benchmarking::account::<T::AccountId>("successful_origin", 0, 0); + crate::Pallet::<T, I>::do_add_member_to_rank(who.clone(), *min_rank) + .expect("Could not add members for benchmarks"); + Ok(frame_system::RawOrigin::Signed(who).into()) } } @@ -285,7 +314,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi type Success = T::AccountId; fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> { - let who = frame_system::EnsureSigned::try_origin(o)?; + let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?; match Members::<T, I>::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(who), _ => Err(frame_system::RawOrigin::Signed(who).into()), @@ -294,10 +323,16 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi #[cfg(feature = "runtime-benchmarks")] fn try_successful_origin() -> Result<T::RuntimeOrigin, ()> { - EnsureRankedMember::<T, I, MIN_RANK>::try_successful_origin() + <EnsureRankedMember<T, I, MIN_RANK> as EnsureOrigin<_>>::try_successful_origin() } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl<{ T: Config<I>, I: 'static, const MIN_RANK: u16, A }> + EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureMember<T, I, MIN_RANK> + {} +} + /// Guard to ensure that the given origin is a member of the collective. The pair of both the /// account ID and the rank of the member is the `Success` value. pub struct EnsureRankedMember<T, I, const MIN_RANK: u16>(PhantomData<(T, I)>); @@ -307,7 +342,7 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi type Success = (T::AccountId, Rank); fn try_origin(o: T::RuntimeOrigin) -> Result<Self::Success, T::RuntimeOrigin> { - let who = frame_system::EnsureSigned::try_origin(o)?; + let who = <frame_system::EnsureSigned<_> as EnsureOrigin<_>>::try_origin(o)?; match Members::<T, I>::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok((who, rank)), _ => Err(frame_system::RawOrigin::Signed(who).into()), @@ -323,6 +358,12 @@ impl<T: Config<I>, I: 'static, const MIN_RANK: u16> EnsureOrigin<T::RuntimeOrigi } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl<{ T: Config<I>, I: 'static, const MIN_RANK: u16, A }> + EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureRankedMember<T, I, MIN_RANK> + {} +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -708,6 +749,15 @@ pub mod pallet { } Ok(()) } + + /// Determine the rank of the account behind the `Signed` origin `o`, `None` if the account + /// is unknown to this collective or `o` is not `Signed`. + pub fn as_rank( + o: &<T::RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin, + ) -> Option<u16> { + use frame_support::traits::CallerTrait; + o.as_signed().and_then(Self::rank_of) + } } impl<T: Config<I>, I: 'static> RankedMembers for Pallet<T, I> { diff --git a/substrate/frame/ranked-collective/src/tests.rs b/substrate/frame/ranked-collective/src/tests.rs index 04519bc0f8e2247a62b59842a0acbb32cd3fe31f..338dcaacedcf74fd9352e125bd30d6897cda4029 100644 --- a/substrate/frame/ranked-collective/src/tests.rs +++ b/substrate/frame/ranked-collective/src/tests.rs @@ -464,34 +464,52 @@ fn ensure_ranked_works() { type Rank2 = EnsureRanked<Test, (), 2>; type Rank3 = EnsureRanked<Test, (), 3>; type Rank4 = EnsureRanked<Test, (), 4>; - assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(1)).unwrap(), 1); - assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); - assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!(<Rank1 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1)).unwrap(), 1); + assert_eq!(<Rank1 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); + assert_eq!(<Rank1 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); assert_eq!( - Rank2::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + <Rank2 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1)) + .unwrap_err() + .into_signer() + .unwrap(), 1 ); - assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); - assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!(<Rank2 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); + assert_eq!(<Rank2 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); assert_eq!( - Rank3::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + <Rank3 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1)) + .unwrap_err() + .into_signer() + .unwrap(), 1 ); assert_eq!( - Rank3::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(), + <Rank3 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2)) + .unwrap_err() + .into_signer() + .unwrap(), 2 ); - assert_eq!(Rank3::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!(<Rank3 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); assert_eq!( - Rank4::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + <Rank4 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(1)) + .unwrap_err() + .into_signer() + .unwrap(), 1 ); assert_eq!( - Rank4::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(), + <Rank4 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(2)) + .unwrap_err() + .into_signer() + .unwrap(), 2 ); assert_eq!( - Rank4::try_origin(RuntimeOrigin::signed(3)).unwrap_err().as_signed().unwrap(), + <Rank4 as EnsureOrigin<_>>::try_origin(RuntimeOrigin::signed(3)) + .unwrap_err() + .into_signer() + .unwrap(), 3 ); }); diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs index 288c65feae5679e7399a0b1623172f9e507ed6c5..4c332a3048d0bf08adbc80bada5fe0f1d5b2e6ad 100644 --- a/substrate/frame/referenda/src/benchmarking.rs +++ b/substrate/frame/referenda/src/benchmarking.rs @@ -26,7 +26,7 @@ use frame_benchmarking::v1::{ use frame_support::{ assert_ok, dispatch::UnfilteredDispatchable, - traits::{Bounded, Currency, EnsureOrigin}, + traits::{Bounded, Currency, EnsureOrigin, EnsureOriginWithArg}, }; use frame_system::RawOrigin; use sp_runtime::traits::Bounded as ArithBounded; @@ -196,7 +196,7 @@ fn is_not_confirming<T: Config<I>, I: 'static>(index: ReferendumIndex) -> bool { benchmarks_instance_pallet! { submit { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::<T, I>::max_value()); whitelist_account!(caller); @@ -213,7 +213,7 @@ benchmarks_instance_pallet! { place_decision_deposit_preparing { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); }: place_decision_deposit<T::RuntimeOrigin>(origin, index) verify { @@ -222,7 +222,7 @@ benchmarks_instance_pallet! { place_decision_deposit_queued { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); fill_queue::<T, I>(origin.clone(), index, 1, 90); }: place_decision_deposit<T::RuntimeOrigin>(origin, index) @@ -234,7 +234,7 @@ benchmarks_instance_pallet! { place_decision_deposit_not_queued { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); fill_queue::<T, I>(origin.clone(), index, 0, 90); let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track; @@ -248,7 +248,7 @@ benchmarks_instance_pallet! { place_decision_deposit_passing { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); skip_prepare_period::<T, I>(index); make_passing::<T, I>(index); @@ -259,7 +259,7 @@ benchmarks_instance_pallet! { place_decision_deposit_failing { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); skip_prepare_period::<T, I>(index); }: place_decision_deposit<T::RuntimeOrigin>(origin, index) @@ -269,7 +269,7 @@ benchmarks_instance_pallet! { refund_decision_deposit { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); place_deposit::<T, I>(index); assert_ok!(Referenda::<T, I>::cancel( @@ -284,7 +284,7 @@ benchmarks_instance_pallet! { refund_submission_deposit { let origin = - T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?; let index = create_referendum::<T, I>(origin.clone()); let caller = frame_system::ensure_signed(origin.clone()).unwrap(); let balance = T::Currency::free_balance(&caller); @@ -303,7 +303,7 @@ benchmarks_instance_pallet! { } cancel { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -315,7 +315,7 @@ benchmarks_instance_pallet! { } kill { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -327,7 +327,7 @@ benchmarks_instance_pallet! { } one_fewer_deciding_queue_empty { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -346,7 +346,7 @@ benchmarks_instance_pallet! { } one_fewer_deciding_failing { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin.clone()); // No spaces free in the queue. @@ -371,7 +371,7 @@ benchmarks_instance_pallet! { } one_fewer_deciding_passing { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin.clone()); // No spaces free in the queue. @@ -396,7 +396,7 @@ benchmarks_instance_pallet! { } nudge_referendum_requeued_insertion { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. let index = create_referendum::<T, I>(origin.clone()); @@ -419,7 +419,7 @@ benchmarks_instance_pallet! { } nudge_referendum_requeued_slide { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. let index = create_referendum::<T, I>(origin.clone()); @@ -447,7 +447,7 @@ benchmarks_instance_pallet! { // free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the // insertion at the beginning. - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. let index = create_referendum::<T, I>(origin.clone()); @@ -466,7 +466,7 @@ benchmarks_instance_pallet! { } nudge_referendum_not_queued { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. let index = create_referendum::<T, I>(origin.clone()); @@ -485,7 +485,7 @@ benchmarks_instance_pallet! { } nudge_referendum_no_deposit { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); skip_prepare_period::<T, I>(index); @@ -496,7 +496,7 @@ benchmarks_instance_pallet! { } nudge_referendum_preparing { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -507,7 +507,7 @@ benchmarks_instance_pallet! { } nudge_referendum_timed_out { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); skip_timeout_period::<T, I>(index); @@ -518,7 +518,7 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_failing { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -529,7 +529,7 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_passing { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -541,7 +541,7 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_confirming { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -555,7 +555,7 @@ benchmarks_instance_pallet! { } nudge_referendum_end_confirming { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -570,7 +570,7 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_not_confirming { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -586,7 +586,7 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_confirming { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -601,7 +601,7 @@ benchmarks_instance_pallet! { } nudge_referendum_approved { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -616,7 +616,7 @@ benchmarks_instance_pallet! { } nudge_referendum_rejected { - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin); place_deposit::<T, I>(index); @@ -632,7 +632,7 @@ benchmarks_instance_pallet! { set_some_metadata { use sp_std::borrow::Cow; - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin.clone()); let hash = T::Preimages::note(Cow::from(vec![5, 6])).unwrap(); @@ -643,7 +643,7 @@ benchmarks_instance_pallet! { clear_metadata { use sp_std::borrow::Cow; - let origin = T::SubmitOrigin::try_successful_origin() + let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()) .expect("SubmitOrigin has no successful origin required for the benchmark"); let index = create_referendum::<T, I>(origin.clone()); let hash = T::Preimages::note(Cow::from(vec![6, 7, 8])).unwrap(); diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs index dd352d0af40cbceb4b62544ba3129b41927e2917..3756257c33fe524761578e327bea3006134afee3 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -138,7 +138,7 @@ const ASSEMBLY_ID: LockIdentifier = *b"assembly"; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg}; use frame_system::pallet_prelude::*; /// The current storage version. @@ -167,7 +167,11 @@ pub mod pallet { type Currency: ReservableCurrency<Self::AccountId>; // Origins and unbalances. /// Origin from which proposals may be submitted. - type SubmitOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>; + type SubmitOrigin: EnsureOriginWithArg< + Self::RuntimeOrigin, + PalletsOriginOf<Self>, + Success = Self::AccountId, + >; /// Origin from which any vote may be cancelled. type CancelOrigin: EnsureOrigin<Self::RuntimeOrigin>; /// Origin from which any vote may be killed. @@ -430,7 +434,8 @@ pub mod pallet { proposal: BoundedCallOf<T, I>, enactment_moment: DispatchTime<T::BlockNumber>, ) -> DispatchResult { - let who = T::SubmitOrigin::ensure_origin(origin)?; + let proposal_origin = *proposal_origin; + let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?; let track = T::Tracks::track_for(&proposal_origin).map_err(|_| Error::<T, I>::NoTrack)?; @@ -445,7 +450,7 @@ pub mod pallet { T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?; let status = ReferendumStatus { track, - origin: *proposal_origin, + origin: proposal_origin, proposal: proposal.clone(), enactment: enactment_moment, submitted: now, diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs index d92bee48d6aa5d4e77e468fdf10fd510b122856a..4ac853ce8e89a5f4c1e379192dba2ba662421dea 100644 --- a/substrate/frame/society/src/lib.rs +++ b/substrate/frame/society/src/lib.rs @@ -252,10 +252,11 @@ mod mock; mod tests; use frame_support::{ + impl_ensure_origin_with_arg_ignoring_arg, pallet_prelude::*, traits::{ - BalanceStatus, ChangeMembers, Currency, EnsureOrigin, ExistenceRequirement::AllowDeath, - Imbalance, OnUnbalanced, Randomness, ReservableCurrency, + BalanceStatus, ChangeMembers, Currency, EnsureOrigin, EnsureOriginWithArg, + ExistenceRequirement::AllowDeath, Imbalance, OnUnbalanced, Randomness, ReservableCurrency, }, PalletId, }; @@ -1181,6 +1182,12 @@ impl<T: Config> EnsureOrigin<T::RuntimeOrigin> for EnsureFounder<T> { } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl<{ T: Config, A }> + EnsureOriginWithArg<T::RuntimeOrigin, A> for EnsureFounder<T> + {} +} + /// Pick an item at pseudo-random from the slice, given the `rng`. `None` iff the slice is empty. fn pick_item<'a, R: RngCore, T>(rng: &mut R, items: &'a [T]) -> Option<&'a T> { if items.is_empty() { diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs index e48a70a9df97314d366fb8894ce69121c4707ba6..0eaa73f603068fab4b9ef9b592b44bf6219081ca 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -418,6 +418,34 @@ fn expand_origin_pallet_conversions( } } } + + #attr + impl<'a> TryFrom<&'a OriginCaller> for &'a #pallet_origin { + type Error = (); + fn try_from( + x: &'a OriginCaller, + ) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> { + if let OriginCaller::#variant_name(l) = x { + Ok(&l) + } else { + Err(()) + } + } + } + + #attr + impl<'a> TryFrom<&'a RuntimeOrigin> for &'a #pallet_origin { + type Error = (); + fn try_from( + x: &'a RuntimeOrigin, + ) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> { + if let OriginCaller::#variant_name(l) = &x.caller { + Ok(&l) + } else { + Err(()) + } + } + } } } diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 47c7b22f5bf158e5cb29a034c68a265a06229972..8164b8361af87efa06b82268560bd84f104539e5 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -89,6 +89,26 @@ impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> { } } +impl<AccountId> RawOrigin<AccountId> { + /// Returns `Some` with a reference to the `AccountId` if `self` is `Signed`, `None` otherwise. + pub fn as_signed(&self) -> Option<&AccountId> { + match &self { + Self::Signed(x) => Some(x), + _ => None, + } + } + + /// Returns `true` if `self` is `Root`, `None` otherwise. + pub fn is_root(&self) -> bool { + matches!(&self, Self::Root) + } + + /// Returns `true` if `self` is `None`, `None` otherwise. + pub fn is_none(&self) -> bool { + matches!(&self, Self::None) + } +} + /// A type that can be used as a parameter in a dispatchable function. /// /// When using `decl_module` all arguments for call functions must implement this trait. diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 3db274c1720c67efec0f86e98cd5d0df1941af07..e4fd04750441a7781e4352fe2b5ed8ecb9b246c6 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -98,7 +98,7 @@ pub use dispatch::EnsureOneOf; pub use dispatch::{ AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin, EnsureOriginEqualOrHigherPrivilege, EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, - OriginTrait, TryMapSuccess, UnfilteredDispatchable, + OriginTrait, TryMapSuccess, TryWithMorphedArg, UnfilteredDispatchable, }; mod voting; diff --git a/substrate/frame/support/src/traits/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs index 6961e69ba5750de94c1505823d39a538b7421e8f..9ea58479a0dfee384d1fb34c23e7d47947c5ffb4 100644 --- a/substrate/frame/support/src/traits/dispatch.rs +++ b/substrate/frame/support/src/traits/dispatch.rs @@ -48,19 +48,6 @@ pub trait EnsureOrigin<OuterOrigin> { fn try_successful_origin() -> Result<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 try_successful_origin() -> Result<OO, ()> { - Err(()) - } -} - /// [`EnsureOrigin`] implementation that checks that an origin has equal or higher privilege /// compared to the expected `Origin`. /// @@ -166,6 +153,62 @@ pub trait EnsureOriginWithArg<OuterOrigin, Argument> { fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()>; } +/// Simple macro to explicitly implement [EnsureOriginWithArg] to be used on any type which +/// implements [EnsureOrigin]. This is quick and dirty, so you must use the type parameters `O` +/// (the origin type), `T` (the argument type) and `AccountId` (if you are using the `O: ..` form). +/// +/// The argument is ignored, much like in [AsEnsureOriginWithArg]. +#[macro_export] +macro_rules! impl_ensure_origin_with_arg_ignoring_arg { + ( impl < { O: .., I: 'static, $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => { + impl_ensure_origin_with_arg_ignoring_arg! { + impl <{ + O: Into<Result<RawOrigin<AccountId, I>, O>> + From<RawOrigin<AccountId, I>>, + I: 'static, + $( $bound )* + }> EnsureOriginWithArg<O, $t_param> for $name {} + } + }; + ( impl < { O: .. , $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => { + impl_ensure_origin_with_arg_ignoring_arg! { + impl <{ + O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, + $( $bound )* + }> EnsureOriginWithArg<O, $t_param> for $name {} + } + }; + ( impl < { $( $bound:tt )* } > EnsureOriginWithArg<$o_param:ty, $t_param:ty> for $name:ty {} ) => { + impl < $( $bound )* > EnsureOriginWithArg<$o_param, $t_param> for $name { + type Success = <Self as EnsureOrigin<$o_param>>::Success; + fn try_origin(o: $o_param, _: &$t_param) -> Result<Self::Success, $o_param> { + <Self as EnsureOrigin<$o_param>>::try_origin(o) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(_: &$t_param) -> Result<$o_param, ()> { + <Self as EnsureOrigin<$o_param>>::try_successful_origin() + } + } + } +} + +/// [`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 try_successful_origin() -> Result<OO, ()> { + Err(()) + } +} +impl_ensure_origin_with_arg_ignoring_arg! { + impl<{ OO, Success, A }> + EnsureOriginWithArg<OO, A> for NeverEnsureOrigin<Success> + {} +} + pub struct AsEnsureOriginWithArg<EO>(sp_std::marker::PhantomData<EO>); impl<OuterOrigin, Argument, EO: EnsureOrigin<OuterOrigin>> EnsureOriginWithArg<OuterOrigin, Argument> for AsEnsureOriginWithArg<EO> @@ -207,6 +250,18 @@ impl<O, Original: EnsureOrigin<O>, Mutator: Morph<Original::Success>> EnsureOrig Original::try_successful_origin() } } +impl<O, Original: EnsureOriginWithArg<O, A>, Mutator: Morph<Original::Success>, A> + EnsureOriginWithArg<O, A> for MapSuccess<Original, Mutator> +{ + type Success = Mutator::Outcome; + fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> { + Ok(Mutator::morph(Original::try_origin(o, a)?)) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &A) -> Result<O, ()> { + Original::try_successful_origin(a) + } +} /// A derivative `EnsureOrigin` implementation. It mutates the `Success` result of an `Original` /// implementation with a given `Mutator`, allowing the possibility of an error to be returned @@ -228,6 +283,43 @@ impl<O: Clone, Original: EnsureOrigin<O>, Mutator: TryMorph<Original::Success>> Original::try_successful_origin() } } +impl<O: Clone, Original: EnsureOriginWithArg<O, A>, Mutator: TryMorph<Original::Success>, A> + EnsureOriginWithArg<O, A> for TryMapSuccess<Original, Mutator> +{ + type Success = Mutator::Outcome; + fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> { + let orig = o.clone(); + Mutator::try_morph(Original::try_origin(o, a)?).map_err(|()| orig) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &A) -> Result<O, ()> { + Original::try_successful_origin(a) + } +} + +pub struct TryWithMorphedArg<O, A, Morph, Inner, Success>( + PhantomData<(O, A, Morph, Inner, Success)>, +); +impl< + O, + A, + Morph: for<'a> TryMorph<&'a A>, + Inner: for<'a> EnsureOriginWithArg<O, <Morph as TryMorph<&'a A>>::Outcome, Success = Success>, + Success, + > EnsureOriginWithArg<O, A> for TryWithMorphedArg<O, A, Morph, Inner, Success> +{ + type Success = Success; + fn try_origin(o: O, a: &A) -> Result<Success, O> { + match Morph::try_morph(a) { + Ok(x) => Inner::try_origin(o, &x), + _ => return Err(o), + } + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &A) -> Result<O, ()> { + Inner::try_successful_origin(&Morph::try_morph(a).map_err(|_| ())?) + } +} /// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` /// and `R`, with them combined using an `Either` type. @@ -250,6 +342,24 @@ impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>> L::try_successful_origin().or_else(|()| R::try_successful_origin()) } } +impl< + OuterOrigin, + L: EnsureOriginWithArg<OuterOrigin, Argument>, + R: EnsureOriginWithArg<OuterOrigin, Argument>, + Argument, + > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOfDiverse<L, R> +{ + type Success = Either<L::Success, R::Success>; + fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> { + L::try_origin(o, a) + .map_or_else(|o| R::try_origin(o, a).map(Either::Right), |o| Ok(Either::Left(o))) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> { + L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a)) + } +} /// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L` /// and `R`, with them combined using an `Either` type. @@ -283,6 +393,23 @@ impl< L::try_successful_origin().or_else(|()| R::try_successful_origin()) } } +impl< + OuterOrigin, + L: EnsureOriginWithArg<OuterOrigin, Argument>, + R: EnsureOriginWithArg<OuterOrigin, Argument, Success = L::Success>, + Argument, + > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOf<L, R> +{ + type Success = L::Success; + fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> { + L::try_origin(o, a).or_else(|o| R::try_origin(o, a)) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> { + L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a)) + } +} /// Type that can be dispatched with an origin but without checking the origin filter. /// @@ -306,6 +433,21 @@ pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId> /// Extract a reference to the system-level `RawOrigin` if it is that. fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>; + + /// Extract the signer from it if a system `Signed` origin, `None` otherwise. + fn as_signed(&self) -> Option<&AccountId> { + self.as_system_ref().and_then(RawOrigin::as_signed) + } + + /// Returns `true` if `self` is a system `Root` origin, `None` otherwise. + fn is_root(&self) -> bool { + self.as_system_ref().map_or(false, RawOrigin::is_root) + } + + /// Returns `true` if `self` is a system `None` origin, `None` otherwise. + fn is_none(&self) -> bool { + self.as_system_ref().map_or(false, RawOrigin::is_none) + } } /// Methods available on `frame_system::Config::RuntimeOrigin`. @@ -356,7 +498,13 @@ pub trait OriginTrait: Sized { fn signed(by: Self::AccountId) -> Self; /// Extract the signer from the message if it is a `Signed` origin. + #[deprecated = "Use `into_signer` instead"] fn as_signed(self) -> Option<Self::AccountId> { + self.into_signer() + } + + /// Extract the signer from the message if it is a `Signed` origin. + fn into_signer(self) -> Option<Self::AccountId> { self.into_caller().into_system().and_then(|s| { if let RawOrigin::Signed(who) = s { Some(who) diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index a48a1e459f32ab3caaea755d1d6db586cd8457a7..cbda3d55cc68ccc703fc89314088fc97c7852776 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -89,10 +89,11 @@ use frame_support::{ extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, }, + impl_ensure_origin_with_arg_ignoring_arg, storage::{self, StorageStreamIter}, traits::{ - ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, - OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, + ConstU32, Contains, EnsureOrigin, EnsureOriginWithArg, Get, HandleLifetime, + OnKilledAccount, OnNewAccount, OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, }, Parameter, }; @@ -265,7 +266,7 @@ pub mod pallet { type RuntimeOrigin: Into<Result<RawOrigin<Self::AccountId>, Self::RuntimeOrigin>> + From<RawOrigin<Self::AccountId>> + Clone - + OriginTrait<Call = Self::RuntimeCall>; + + OriginTrait<Call = Self::RuntimeCall, AccountId = Self::AccountId>; /// The aggregated `RuntimeCall` type. #[pallet::no_default] @@ -823,6 +824,12 @@ impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, Acco } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., AccountId: Decode, T } > + EnsureOriginWithArg<O, T> for EnsureRoot<AccountId> + {} +} + /// Ensure the origin is Root and return the provided `Success` value. pub struct EnsureRootWithSuccess<AccountId, Success>( sp_std::marker::PhantomData<(AccountId, Success)>, @@ -847,6 +854,12 @@ impl< } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., AccountId: Decode, Success: TypedGet, T } > + EnsureOriginWithArg<O, T> for EnsureRootWithSuccess<AccountId, Success> + {} +} + /// Ensure the origin is provided `Ensure` origin and return the provided `Success` value. pub struct EnsureWithSuccess<Ensure, AccountId, Success>( sp_std::marker::PhantomData<(Ensure, AccountId, Success)>, @@ -892,6 +905,12 @@ impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, Acco } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., AccountId: Decode, T } > + EnsureOriginWithArg<O, T> for EnsureSigned<AccountId> + {} +} + /// Ensure the origin is `Signed` origin from the given `AccountId`. pub struct EnsureSignedBy<Who, AccountId>(sp_std::marker::PhantomData<(Who, AccountId)>); impl< @@ -918,6 +937,12 @@ impl< } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., Who: SortedMembers<AccountId>, AccountId: PartialEq + Clone + Ord + Decode, T } > + EnsureOriginWithArg<O, T> for EnsureSignedBy<Who, AccountId> + {} +} + /// Ensure the origin is `None`. i.e. unsigned transaction. pub struct EnsureNone<AccountId>(sp_std::marker::PhantomData<AccountId>); impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, AccountId> @@ -937,10 +962,16 @@ impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, Acco } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O: .., AccountId, T } > + EnsureOriginWithArg<O, T> for EnsureNone<AccountId> + {} +} + /// Always fail. -pub struct EnsureNever<T>(sp_std::marker::PhantomData<T>); -impl<O, T> EnsureOrigin<O> for EnsureNever<T> { - type Success = T; +pub struct EnsureNever<Success>(sp_std::marker::PhantomData<Success>); +impl<O, Success> EnsureOrigin<O> for EnsureNever<Success> { + type Success = Success; fn try_origin(o: O) -> Result<Self::Success, O> { Err(o) } @@ -951,6 +982,12 @@ impl<O, T> EnsureOrigin<O> for EnsureNever<T> { } } +impl_ensure_origin_with_arg_ignoring_arg! { + impl< { O, Success, T } > + EnsureOriginWithArg<O, T> for EnsureNever<Success> + {} +} + /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction). /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise. pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, BadOrigin> diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs index 05a7e96fdecb13fa6d9b2c3ac7bdd3ab7814eaa5..165df688b1c2c2915bfdb932a9e1d0448d31b680 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -746,19 +746,20 @@ fn ensure_signed_stuff_works() { } let signed_origin = RuntimeOrigin::signed(0u64); - assert_ok!(EnsureSigned::try_origin(signed_origin.clone())); - assert_ok!(EnsureSignedBy::<Members, _>::try_origin(signed_origin)); + assert_ok!(<EnsureSigned<_> as EnsureOrigin<_>>::try_origin(signed_origin.clone())); + assert_ok!(<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_origin(signed_origin)); #[cfg(feature = "runtime-benchmarks")] { - let successful_origin: RuntimeOrigin = EnsureSigned::try_successful_origin() - .expect("EnsureSigned has no successful origin required for the test"); - assert_ok!(EnsureSigned::try_origin(successful_origin)); + let successful_origin: RuntimeOrigin = + <EnsureSigned<_> as EnsureOrigin<_>>::try_successful_origin() + .expect("EnsureSigned has no successful origin required for the test"); + assert_ok!(<EnsureSigned<_> as EnsureOrigin<_>>::try_origin(successful_origin)); let successful_origin: RuntimeOrigin = - EnsureSignedBy::<Members, _>::try_successful_origin() + <EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_successful_origin() .expect("EnsureSignedBy has no successful origin required for the test"); - assert_ok!(EnsureSignedBy::<Members, _>::try_origin(successful_origin)); + assert_ok!(<EnsureSignedBy<Members, _> as EnsureOrigin<_>>::try_origin(successful_origin)); } } diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index a6155e6a4f808f7aaf26884bc5c86c8d5783c22f..9c09bad21d9bc8e3d239b8b1e99b719fc571e261 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -339,6 +339,33 @@ impl<T, A: TryInto<T>> TryMorph<A> for TryMorphInto<T> { } } +/// Implementation of `Morph` to retrieve just the first element of a tuple. +pub struct TakeFirst; +impl<T1> Morph<(T1,)> for TakeFirst { + type Outcome = T1; + fn morph(a: (T1,)) -> T1 { + a.0 + } +} +impl<T1, T2> Morph<(T1, T2)> for TakeFirst { + type Outcome = T1; + fn morph(a: (T1, T2)) -> T1 { + a.0 + } +} +impl<T1, T2, T3> Morph<(T1, T2, T3)> for TakeFirst { + type Outcome = T1; + fn morph(a: (T1, T2, T3)) -> T1 { + a.0 + } +} +impl<T1, T2, T3, T4> Morph<(T1, T2, T3, T4)> for TakeFirst { + type Outcome = T1; + fn morph(a: (T1, T2, T3, T4)) -> T1 { + a.0 + } +} + /// Create a `Morph` and/or `TryMorph` impls with a simple closure-like expression. /// /// # Examples