frame-support: Introduce EnsureOriginOrHigherPrivilege (#12844)

* frame-support: Introduce `EnsureOriginOrHigherPrivilege`

This adds a new `EnsureOrigin` implementation that checks if a given origin matches or if the origin
is has a higher or equal origin matches or if the origin is has a higher or equal privilege.

* FMT
This commit is contained in:
Bastian Köcher
2022-12-06 15:58:52 +01:00
committed by GitHub
parent aa21e56744
commit 72a7fa035b
2 changed files with 91 additions and 5 deletions
+2 -2
View File
@@ -99,8 +99,8 @@ mod dispatch;
pub use dispatch::EnsureOneOf;
pub use dispatch::{
AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin,
EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess,
UnfilteredDispatchable,
EnsureOriginEqualOrHigherPrivilege, EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin,
OriginTrait, TryMapSuccess, UnfilteredDispatchable,
};
mod voting;
+89 -3
View File
@@ -20,10 +20,12 @@
use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin};
use codec::MaxEncodedLen;
use sp_runtime::{
traits::{BadOrigin, Member, Morph, TryMorph},
traits::{BadOrigin, Get, Member, Morph, TryMorph},
Either,
};
use sp_std::marker::PhantomData;
use sp_std::{cmp::Ordering, marker::PhantomData};
use super::misc;
/// Some sort of check on the origin is performed by this object.
pub trait EnsureOrigin<OuterOrigin> {
@@ -59,7 +61,7 @@ pub trait EnsureOrigin<OuterOrigin> {
}
}
/// `EnsureOrigin` implementation that always fails.
/// [`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;
@@ -72,6 +74,90 @@ impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
}
}
/// [`EnsureOrigin`] implementation that checks that an origin has equal or higher privilege
/// compared to the expected `Origin`.
///
/// It will take the shortcut of comparing the incoming origin with the expected `Origin` and if
/// both are the same the origin is accepted.
///
/// # Example
///
/// ```rust
/// # use frame_support::traits::{EnsureOriginEqualOrHigherPrivilege, PrivilegeCmp, EnsureOrigin as _};
/// # use sp_runtime::traits::{parameter_types, Get};
/// # use sp_std::cmp::Ordering;
///
/// #[derive(Eq, PartialEq, Debug)]
/// pub enum Origin {
/// Root,
/// SomethingBelowRoot,
/// NormalUser,
/// }
///
/// struct OriginPrivilegeCmp;
///
/// impl PrivilegeCmp<Origin> for OriginPrivilegeCmp {
/// fn cmp_privilege(left: &Origin, right: &Origin) -> Option<Ordering> {
/// match (left, right) {
/// (Origin::Root, Origin::Root) => Some(Ordering::Equal),
/// (Origin::Root, _) => Some(Ordering::Greater),
/// (Origin::SomethingBelowRoot, Origin::SomethingBelowRoot) => Some(Ordering::Equal),
/// (Origin::SomethingBelowRoot, Origin::Root) => Some(Ordering::Less),
/// (Origin::SomethingBelowRoot, Origin::NormalUser) => Some(Ordering::Greater),
/// (Origin::NormalUser, Origin::NormalUser) => Some(Ordering::Equal),
/// (Origin::NormalUser, _) => Some(Ordering::Less),
/// }
/// }
/// }
///
/// parameter_types! {
/// pub const ExpectedOrigin: Origin = Origin::SomethingBelowRoot;
/// }
///
/// type EnsureOrigin = EnsureOriginEqualOrHigherPrivilege<ExpectedOrigin, OriginPrivilegeCmp>;
///
/// // `Root` has an higher privilege as our expected origin.
/// assert!(EnsureOrigin::ensure_origin(Origin::Root).is_ok());
/// // `SomethingBelowRoot` is exactly the expected origin.
/// assert!(EnsureOrigin::ensure_origin(Origin::SomethingBelowRoot).is_ok());
/// // The `NormalUser` origin is not allowed.
/// assert!(EnsureOrigin::ensure_origin(Origin::NormalUser).is_err());
/// ```
pub struct EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>(
sp_std::marker::PhantomData<(Origin, PrivilegeCmp)>,
);
impl<OuterOrigin, Origin, PrivilegeCmp> EnsureOrigin<OuterOrigin>
for EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>
where
Origin: Get<OuterOrigin>,
OuterOrigin: Eq,
PrivilegeCmp: misc::PrivilegeCmp<OuterOrigin>,
{
type Success = ();
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
let expected_origin = Origin::get();
// If this is the expected origin, it has the same privilege.
if o == expected_origin {
return Ok(())
}
let cmp = PrivilegeCmp::cmp_privilege(&o, &expected_origin);
match cmp {
Some(Ordering::Equal) | Some(Ordering::Greater) => Ok(()),
None | Some(Ordering::Less) => Err(o),
}
}
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<OuterOrigin, ()> {
Ok(Origin::get())
}
}
/// Some sort of check on the origin is performed by this object.
pub trait EnsureOriginWithArg<OuterOrigin, Argument> {
/// A return type.