diff --git a/Cargo.lock b/Cargo.lock index 525c2fe030f4d..9d2d6caa62296 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7586,6 +7586,7 @@ dependencies = [ name = "sp-runtime" version = "2.0.0-rc3" dependencies = [ + "either", "hash256-std-hasher", "impl-trait-for-tuples", "log", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f92189e3c920a..d64f641ea9d5a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -32,6 +32,7 @@ use frame_support::{ }, traits::{Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier}, }; +use frame_system::{EnsureRoot, EnsureOneOf}; use frame_support::traits::{Filter, InstanceFilter}; use codec::{Encode, Decode}; use sp_core::{ @@ -96,7 +97,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 252, - impl_version: 0, + impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, }; @@ -410,7 +411,11 @@ impl pallet_staking::Trait for Runtime { type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; /// A super-majority of the council can cancel the slash. - type SlashCancelOrigin = pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>; + type SlashCancelOrigin = EnsureOneOf< + AccountId, + EnsureRoot, + pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective> + >; type SessionInterface = Self; type RewardCurve = RewardCurve; type NextNewSession = Session; @@ -528,13 +533,18 @@ impl pallet_collective::Trait for Runtime { type MaxProposals = TechnicalMaxProposals; } +type EnsureRootOrHalfCouncil = EnsureOneOf< + AccountId, + EnsureRoot, + pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective> +>; impl pallet_membership::Trait for Runtime { type Event = Event; - type AddOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; - type RemoveOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; - type SwapOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; - type ResetOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; - type PrimeOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + type AddOrigin = EnsureRootOrHalfCouncil; + type RemoveOrigin = EnsureRootOrHalfCouncil; + type SwapOrigin = EnsureRootOrHalfCouncil; + type ResetOrigin = EnsureRootOrHalfCouncil; + type PrimeOrigin = EnsureRootOrHalfCouncil; type MembershipInitialized = TechnicalCommittee; type MembershipChanged = TechnicalCommittee; } @@ -554,8 +564,16 @@ parameter_types! { impl pallet_treasury::Trait for Runtime { type ModuleId = TreasuryModuleId; type Currency = Balances; - type ApproveOrigin = pallet_collective::EnsureMembers<_4, AccountId, CouncilCollective>; - type RejectOrigin = pallet_collective::EnsureMembers<_2, AccountId, CouncilCollective>; + type ApproveOrigin = EnsureOneOf< + AccountId, + EnsureRoot, + pallet_collective::EnsureMembers<_4, AccountId, CouncilCollective> + >; + type RejectOrigin = EnsureOneOf< + AccountId, + EnsureRoot, + pallet_collective::EnsureMembers<_2, AccountId, CouncilCollective> + >; type Tippers = Elections; type TipCountdown = TipCountdown; type TipFindersFee = TipFindersFee; @@ -734,8 +752,8 @@ impl pallet_identity::Trait for Runtime { type MaxAdditionalFields = MaxAdditionalFields; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; - type ForceOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; - type RegistrarOrigin = pallet_collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + type ForceOrigin = EnsureRootOrHalfCouncil; + type RegistrarOrigin = EnsureRootOrHalfCouncil; } parameter_types! { diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 2b58437685556..eddf89997f9f9 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -78,7 +78,7 @@ use frame_support::{ traits::{Currency, ReservableCurrency, OnUnbalanced, Get, BalanceStatus, EnsureOrigin}, weights::Weight, }; -use frame_system::{self as system, ensure_signed, ensure_root}; +use frame_system::{self as system, ensure_signed}; mod benchmarking; @@ -635,9 +635,7 @@ decl_module! { /// # #[weight = weight_for::add_registrar::(T::MaxRegistrars::get().into()) ] fn add_registrar(origin, account: T::AccountId) -> DispatchResultWithPostInfo { - T::RegistrarOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::RegistrarOrigin::ensure_origin(origin)?; let (i, registrar_count) = >::try_mutate( |registrars| -> Result<(RegistrarIndex, usize), DispatchError> { @@ -1108,9 +1106,7 @@ decl_module! { T::MaxAdditionalFields::get().into(), // X )] fn kill_identity(origin, target: ::Source) -> DispatchResultWithPostInfo { - T::ForceOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::ForceOrigin::ensure_origin(origin)?; // Figure out who we're meant to be clearing. let target = T::Lookup::lookup(target)?; @@ -1435,7 +1431,7 @@ mod tests { new_test_ext().execute_with(|| { assert_ok!(Identity::set_identity(Origin::signed(10), ten())); assert_ok!(Identity::set_subs(Origin::signed(10), vec![(20, Data::Raw(vec![40; 1]))])); - assert_ok!(Identity::kill_identity(Origin::ROOT, 10)); + assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); assert_eq!(Balances::free_balance(10), 80); assert!(Identity::super_of(20).is_none()); }); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 669964c70c177..cfcc17238ae27 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -28,7 +28,7 @@ use frame_support::{ decl_module, decl_storage, decl_event, decl_error, traits::{ChangeMembers, InitializeMembers, EnsureOrigin}, }; -use frame_system::{self as system, ensure_root, ensure_signed}; +use frame_system::{self as system, ensure_signed}; pub trait Trait: frame_system::Trait { /// The overarching event type. @@ -120,9 +120,7 @@ decl_module! { /// May only be called from `AddOrigin` or root. #[weight = 50_000_000] pub fn add_member(origin, who: T::AccountId) { - T::AddOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::AddOrigin::ensure_origin(origin)?; let mut members = >::get(); let location = members.binary_search(&who).err().ok_or(Error::::AlreadyMember)?; @@ -139,9 +137,7 @@ decl_module! { /// May only be called from `RemoveOrigin` or root. #[weight = 50_000_000] pub fn remove_member(origin, who: T::AccountId) { - T::RemoveOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::RemoveOrigin::ensure_origin(origin)?; let mut members = >::get(); let location = members.binary_search(&who).ok().ok_or(Error::::NotMember)?; @@ -161,9 +157,7 @@ decl_module! { /// Prime membership is *not* passed from `remove` to `add`, if extant. #[weight = 50_000_000] pub fn swap_member(origin, remove: T::AccountId, add: T::AccountId) { - T::SwapOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::SwapOrigin::ensure_origin(origin)?; if remove == add { return Ok(()) } @@ -190,9 +184,7 @@ decl_module! { /// May only be called from `ResetOrigin` or root. #[weight = 50_000_000] pub fn reset_members(origin, members: Vec) { - T::ResetOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::ResetOrigin::ensure_origin(origin)?; let mut members = members; members.sort(); @@ -241,9 +233,7 @@ decl_module! { /// Set the prime member. Must be a current member. #[weight = 50_000_000] pub fn set_prime(origin, who: T::AccountId) { - T::PrimeOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::PrimeOrigin::ensure_origin(origin)?; Self::members().binary_search(&who).ok().ok_or(Error::::NotMember)?; Prime::::put(&who); T::MembershipChanged::set_prime(Some(who)); @@ -252,9 +242,7 @@ decl_module! { /// Remove the prime member if it exists. #[weight = 50_000_000] pub fn clear_prime(origin) { - T::PrimeOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::PrimeOrigin::ensure_origin(origin)?; Prime::::kill(); T::MembershipChanged::set_prime(None); } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 11b23443d68b9..35416aa8ebe57 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -47,7 +47,7 @@ use frame_support::{ decl_module, decl_event, decl_storage, ensure, decl_error, traits::{Currency, EnsureOrigin, ReservableCurrency, OnUnbalanced, Get}, }; -use frame_system::{self as system, ensure_signed, ensure_root}; +use frame_system::{self as system, ensure_signed}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; @@ -197,9 +197,7 @@ decl_module! { /// # #[weight = 70_000_000] fn kill_name(origin, target: ::Source) { - T::ForceOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::ForceOrigin::ensure_origin(origin)?; // Figure out who we're meant to be clearing. let target = T::Lookup::lookup(target)?; @@ -225,9 +223,7 @@ decl_module! { /// # #[weight = 70_000_000] fn force_name(origin, target: ::Source, name: Vec) { - T::ForceOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::ForceOrigin::ensure_origin(origin)?; let target = T::Lookup::lookup(target)?; let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index ba56298493a99..5131a663e0e61 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -318,9 +318,7 @@ decl_module! { dest: ::Source, index: u32 ) { - T::KickOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::KickOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(dest)?; @@ -344,9 +342,7 @@ decl_module! { index: u32, score: T::Score ) { - T::ScoreOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::ScoreOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(dest)?; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2a791bfa7ea7b..bd4fb21cb5213 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -1906,9 +1906,7 @@ decl_module! { .saturating_add((35 * WEIGHT_PER_MICROS).saturating_mul(slash_indices.len() as Weight)) ] fn cancel_deferred_slash(origin, era: EraIndex, slash_indices: Vec) { - T::SlashCancelOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::SlashCancelOrigin::ensure_origin(origin)?; ensure!(!slash_indices.is_empty(), Error::::EmptyTargets); ensure!(is_sorted_and_unique(&slash_indices), Error::::NotSortedAndUnique); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 74e71b8cc595d..d702ad779a12f 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -102,7 +102,7 @@ use sp_std::marker::PhantomData; use sp_std::fmt::Debug; use sp_version::RuntimeVersion; use sp_runtime::{ - RuntimeDebug, Perbill, DispatchError, DispatchResult, + RuntimeDebug, Perbill, DispatchError, DispatchResult, Either, generic::{self, Era}, transaction_validity::{ ValidTransaction, TransactionPriority, TransactionLongevity, TransactionValidityError, @@ -847,6 +847,30 @@ impl EnsureOrigin for EnsureNever { } } +/// The "OR gate" implementation of `EnsureOrigin`. +/// +/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first. +pub struct EnsureOneOf(sp_std::marker::PhantomData<(AccountId, L, R)>); +impl< + AccountId, + O: Into, O>> + From>, + L: EnsureOrigin, + R: EnsureOrigin, +> EnsureOrigin for EnsureOneOf { + type Success = Either; + fn try_origin(o: O) -> Result { + L::try_origin(o).map_or_else( + |o| R::try_origin(o).map(|o| Either::Right(o)), + |o| Ok(Either::Left(o)), + ) + } + + #[cfg(feature = "runtime-benchmarks")] + fn successful_origin() -> O { + L::successful_origin() + } +} + /// 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(o: OuterOrigin) -> Result @@ -1879,7 +1903,7 @@ pub(crate) mod tests { use sp_core::H256; use sp_runtime::{traits::{BlakeTwo256, IdentityLookup, SignedExtension}, testing::Header, DispatchError}; use frame_support::{ - impl_outer_origin, parameter_types, assert_ok, assert_noop, + impl_outer_origin, parameter_types, assert_ok, assert_noop, assert_err, weights::WithPostDispatchInfo, }; @@ -2701,4 +2725,15 @@ pub(crate) mod tests { assert!(System::events().len() == 1); }); } + + #[test] + fn ensure_one_of_works() { + fn ensure_root_or_signed(o: RawOrigin) -> Result, Origin> { + EnsureOneOf::, EnsureSigned>::try_origin(o.into()) + } + + assert_ok!(ensure_root_or_signed(RawOrigin::Root), Either::Left(())); + assert_ok!(ensure_root_or_signed(RawOrigin::Signed(0)), Either::Right(0)); + assert_err!(ensure_root_or_signed(RawOrigin::None), Origin::from(RawOrigin::None)); + } } diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index d1fed8fa2860a..861a652e52995 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -102,7 +102,7 @@ use sp_runtime::{Permill, ModuleId, Percent, RuntimeDebug, traits::{ use frame_support::weights::{Weight, DispatchClass}; use frame_support::traits::{Contains, ContainsLengthBound, EnsureOrigin}; use codec::{Encode, Decode}; -use frame_system::{self as system, ensure_signed, ensure_root}; +use frame_system::{self as system, ensure_signed}; mod tests; mod benchmarking; @@ -362,9 +362,7 @@ decl_module! { /// # #[weight = (130_000_000 + T::DbWeight::get().reads_writes(2, 2), DispatchClass::Operational)] fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) { - T::RejectOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::RejectOrigin::ensure_origin(origin)?; let proposal = >::take(&proposal_id).ok_or(Error::::InvalidProposalIndex)?; let value = proposal.bond; @@ -384,9 +382,7 @@ decl_module! { /// # #[weight = (34_000_000 + T::DbWeight::get().reads_writes(2, 1), DispatchClass::Operational)] fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) { - T::ApproveOrigin::try_origin(origin) - .map(|_| ()) - .or_else(ensure_root)?; + T::ApproveOrigin::ensure_origin(origin)?; ensure!(>::contains_key(proposal_id), Error::::InvalidProposalIndex); Approvals::mutate(|v| v.push(proposal_id)); diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index a81c2515c8174..c38faa15a812d 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -28,6 +28,7 @@ impl-trait-for-tuples = "0.1.3" sp-inherents = { version = "2.0.0-rc3", default-features = false, path = "../inherents" } parity-util-mem = { version = "0.6.1", default-features = false, features = ["primitive-types"] } hash256-std-hasher = { version = "0.15.2", default-features = false } +either = { version = "1.5", default-features = false } [dev-dependencies] serde_json = "1.0.41" @@ -51,4 +52,5 @@ std = [ "sp-inherents/std", "parity-util-mem/std", "hash256-std-hasher/std", + "either/use_std", ] diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index fe156fe738773..a8a518fd7b692 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -81,6 +81,8 @@ pub use sp_arithmetic::biguint; pub use random_number_generator::RandomNumberGenerator; +pub use either::Either; + /// An abstraction over justification for a block's validity under a consensus algorithm. /// /// Essentially a finality proof. The exact formulation will vary between consensus