Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
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
16 changes: 8 additions & 8 deletions frame/collective/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,11 +996,11 @@ impl<
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> O {
fn try_successful_origin() -> Result<O, ()> {
let zero_account_id =
AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
.expect("infinite length input; no invalid inputs for type; qed");
O::from(RawOrigin::Member(zero_account_id))
Ok(O::from(RawOrigin::Member(zero_account_id)))
}
}

Expand All @@ -1021,8 +1021,8 @@ impl<
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> O {
O::from(RawOrigin::Members(N, N))
fn try_successful_origin() -> Result<O, ()> {
Ok(O::from(RawOrigin::Members(N, N)))
}
}

Expand All @@ -1046,8 +1046,8 @@ impl<
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> O {
O::from(RawOrigin::Members(1u32, 0u32))
fn try_successful_origin() -> Result<O, ()> {
Ok(O::from(RawOrigin::Members(1u32, 0u32)))
}
}

Expand All @@ -1071,7 +1071,7 @@ impl<
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> O {
O::from(RawOrigin::Members(0u32, 0u32))
fn try_successful_origin() -> Result<O, ()> {
Ok(O::from(RawOrigin::Members(0u32, 0u32)))
}
}
6 changes: 3 additions & 3 deletions frame/society/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1272,9 +1272,9 @@ impl<T: Config> EnsureOrigin<T::Origin> for EnsureFounder<T> {
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> T::Origin {
let founder = Founder::<T>::get().expect("society founder should exist");
T::Origin::from(frame_system::RawOrigin::Signed(founder))
fn try_successful_origin() -> Result<T::Origin, ()> {
let founder = Founder::<T>::get().ok_or(())?;
Ok(T::Origin::from(frame_system::RawOrigin::Signed(founder)))
}
}

Expand Down
224 changes: 156 additions & 68 deletions frame/support/src/traits/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
//! Traits for dealing with dispatching calls and the origin from which they are dispatched.

use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin};
use sp_arithmetic::traits::{CheckedSub, Zero};
use sp_runtime::{
traits::{BadOrigin, Member},
traits::{BadOrigin, Member, Morph, TryMorph},
Either,
};
use sp_std::marker::PhantomData;

use super::TypedGet;

/// Some sort of check on the origin is performed by this object.
pub trait EnsureOrigin<OuterOrigin> {
Expand All @@ -38,9 +42,23 @@ pub trait EnsureOrigin<OuterOrigin> {

/// Returns an outer origin capable of passing `try_origin` check.
///
/// NOTE: This should generally *NOT* be reimplemented. Instead implement
/// `try_successful_origin`.
///
/// ** Should be used for benchmarking only!!! **
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OuterOrigin;
fn successful_origin() -> OuterOrigin {
Self::try_successful_origin().expect("No origin exists which can satisfy the guard")
}

/// Attept to get an outer origin capable of passing `try_origin` check. May return `Err` if it
/// is impossible. Default implementation just uses `successful_origin()`.
///
/// ** Should be used for benchmarking only!!! **
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<OuterOrigin, ()> {
Ok(Self::successful_origin())
}
}

/// `EnsureOrigin` implementation that always fails.
Expand All @@ -51,8 +69,8 @@ impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
Err(o)
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OO {
panic!("No `successful_origin` possible for `NeverEnsureOrigin`")
fn try_successful_origin() -> Result<OO, ()> {
Err(())
}
}

Expand All @@ -71,9 +89,23 @@ pub trait EnsureOriginWithArg<OuterOrigin, Argument> {

/// Returns an outer origin capable of passing `try_origin` check.
///
/// NOTE: This should generally *NOT* be reimplemented. Instead implement
/// `try_successful_origin`.
///
/// ** Should be used for benchmarking only!!! **
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin(a: &Argument) -> OuterOrigin;
fn successful_origin(a: &Argument) -> OuterOrigin {
Self::try_successful_origin(a).expect("No origin exists which can satisfy the guard")
}

/// Attept to get an outer origin capable of passing `try_origin` check. May return `Err` if it
/// is impossible. Default implementation just uses `successful_origin()`.
///
/// ** Should be used for benchmarking only!!! **
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
Ok(Self::successful_origin(a))
}
}

pub struct AsEnsureOriginWithArg<EO>(sp_std::marker::PhantomData<EO>);
Expand All @@ -97,8 +129,121 @@ impl<OuterOrigin, Argument, EO: EnsureOrigin<OuterOrigin>>
///
/// ** Should be used for benchmarking only!!! **
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin(_: &Argument) -> OuterOrigin {
EO::successful_origin()
fn try_successful_origin(_: &Argument) -> Result<OuterOrigin, ()> {
EO::try_successful_origin()
}
}

/// A derivative `EnsureOrigin` implementation. It mutates the `Success` result of an `Original`
/// implementation with a given `Mutator`.
pub struct MapSuccess<Original, Mutator>(PhantomData<(Original, Mutator)>);
impl<O, Original: EnsureOrigin<O>, Mutator: Morph<Original::Success>> EnsureOrigin<O>
for MapSuccess<Original, Mutator>
{
type Success = Mutator::Outcome;
fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
Ok(Mutator::morph(Original::try_origin(o)?))
}
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<O, ()> {
Original::try_successful_origin()
}
}

/// 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
/// from the mutator.
///
/// NOTE: This is strictly worse performance than `MapSuccess` since it clones the original origin
/// value. If possible, use `MapSuccess` instead.
pub struct TryMapSuccess<Orig, Mutator>(PhantomData<(Orig, Mutator)>);
impl<O: Clone, Original: EnsureOrigin<O>, Mutator: TryMorph<Original::Success>> EnsureOrigin<O>
for TryMapSuccess<Original, Mutator>
{
type Success = Mutator::Outcome;
fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
let orig = o.clone();
Mutator::try_morph(Original::try_origin(o)?).map_err(|()| orig)
}
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<O, ()> {
Original::try_successful_origin()
}
}

/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
/// and `R`, with them combined using an `Either` type.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
pub struct EitherOfDiverse<L, R>(sp_std::marker::PhantomData<(L, R)>);
impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
EnsureOrigin<OuterOrigin> for EitherOfDiverse<L, R>
{
type Success = Either<L::Success, R::Success>;
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
L::try_origin(o)
.map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o)))
}

#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<OuterOrigin, ()> {
L::try_successful_origin().or_else(|()| R::try_successful_origin())
}
}

/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
/// and `R`, with them combined using an `Either` type.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
#[deprecated = "Use `EitherOfDiverse` instead"]
pub type EnsureOneOf<L, R> = EitherOfDiverse<L, R>;

/// "OR gate" implementation of `EnsureOrigin`, `Success` type for both `L` and `R` must
/// be equal.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
pub struct EitherOf<L, R>(sp_std::marker::PhantomData<(L, R)>);
impl<
OuterOrigin,
L: EnsureOrigin<OuterOrigin>,
R: EnsureOrigin<OuterOrigin, Success = L::Success>,
> EnsureOrigin<OuterOrigin> for EitherOf<L, R>
{
type Success = L::Success;
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
L::try_origin(o).or_else(|o| R::try_origin(o))
}

#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<OuterOrigin, ()> {
L::try_successful_origin().or_else(|()| R::try_successful_origin())
}
}

/// Mutator which reduces a scalar by a particular amount.
pub struct ReduceBy<N>(PhantomData<N>);
impl<N: TypedGet> TryMorph<N::Type> for ReduceBy<N>
where
N::Type: CheckedSub,
{
type Outcome = N::Type;
fn try_morph(r: N::Type) -> Result<N::Type, ()> {
r.checked_sub(&N::get()).ok_or(())
}
}
impl<N: TypedGet> Morph<N::Type> for ReduceBy<N>
where
N::Type: CheckedSub + Zero,
{
type Outcome = N::Type;
fn morph(r: N::Type) -> N::Type {
r.checked_sub(&N::get()).unwrap_or(Zero::zero())
}
}

Expand Down Expand Up @@ -176,63 +321,6 @@ pub trait OriginTrait: Sized {
fn signed(by: Self::AccountId) -> Self;
}

/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
/// and `R`, with them combined using an `Either` type.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
pub struct EitherOfDiverse<L, R>(sp_std::marker::PhantomData<(L, R)>);

impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
EnsureOrigin<OuterOrigin> for EitherOfDiverse<L, R>
{
type Success = Either<L::Success, R::Success>;
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
L::try_origin(o)
.map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o)))
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OuterOrigin {
L::successful_origin()
}
}

/// "OR gate" implementation of `EnsureOrigin` allowing for different `Success` types for `L`
/// and `R`, with them combined using an `Either` type.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
#[deprecated = "Use `EitherOfDiverse` instead"]
pub type EnsureOneOf<L, R> = EitherOfDiverse<L, R>;

/// "OR gate" implementation of `EnsureOrigin`, `Success` type for both `L` and `R` must
/// be equal.
///
/// Origin check will pass if `L` or `R` origin check passes. `L` is tested first.
///
/// Successful origin is derived from the left side.
pub struct EitherOf<L, R>(sp_std::marker::PhantomData<(L, R)>);

impl<
OuterOrigin,
L: EnsureOrigin<OuterOrigin>,
R: EnsureOrigin<OuterOrigin, Success = L::Success>,
> EnsureOrigin<OuterOrigin> for EitherOf<L, R>
{
type Success = L::Success;
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
L::try_origin(o).or_else(|o| R::try_origin(o))
}

#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> OuterOrigin {
L::successful_origin()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -248,8 +336,8 @@ mod tests {
Ok(V::get())
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> () {
()
fn try_successful_origin() -> Result<(), ()> {
Ok(())
}
}

Expand All @@ -259,8 +347,8 @@ mod tests {
Err(())
}
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> () {
()
fn try_successful_origin() -> Result<(), ()> {
Err(())
}
}

Expand Down
Loading