1use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin};
21use codec::MaxEncodedLen;
22use core::{cmp::Ordering, marker::PhantomData};
23use sp_runtime::{
24 traits::{BadOrigin, Get, Member, Morph, TryMorph},
25 transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction},
26 Either,
27};
28use sp_weights::Weight;
29
30use super::misc;
31
32pub trait EnsureOrigin<OuterOrigin> {
34 type Success;
36
37 fn ensure_origin(o: OuterOrigin) -> Result<Self::Success, BadOrigin> {
39 Self::try_origin(o).map_err(|_| BadOrigin)
40 }
41
42 fn ensure_origin_or_root(o: OuterOrigin) -> Result<Option<Self::Success>, BadOrigin>
45 where
46 OuterOrigin: OriginTrait,
47 {
48 if o.caller().is_root() {
49 return Ok(None)
50 } else {
51 Self::ensure_origin(o).map(Some)
52 }
53 }
54
55 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin>;
57
58 fn try_origin_or_root(o: OuterOrigin) -> Result<Option<Self::Success>, OuterOrigin>
61 where
62 OuterOrigin: OriginTrait,
63 {
64 if o.caller().is_root() {
65 return Ok(None)
66 } else {
67 Self::try_origin(o).map(Some)
68 }
69 }
70
71 #[cfg(feature = "runtime-benchmarks")]
76 fn try_successful_origin() -> Result<OuterOrigin, ()>;
77}
78
79pub struct EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>(
129 core::marker::PhantomData<(Origin, PrivilegeCmp)>,
130);
131
132impl<OuterOrigin, Origin, PrivilegeCmp> EnsureOrigin<OuterOrigin>
133 for EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>
134where
135 Origin: Get<OuterOrigin>,
136 OuterOrigin: Eq,
137 PrivilegeCmp: misc::PrivilegeCmp<OuterOrigin>,
138{
139 type Success = ();
140
141 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
142 let expected_origin = Origin::get();
143
144 if o == expected_origin {
146 return Ok(())
147 }
148
149 let cmp = PrivilegeCmp::cmp_privilege(&o, &expected_origin);
150
151 match cmp {
152 Some(Ordering::Equal) | Some(Ordering::Greater) => Ok(()),
153 None | Some(Ordering::Less) => Err(o),
154 }
155 }
156
157 #[cfg(feature = "runtime-benchmarks")]
158 fn try_successful_origin() -> Result<OuterOrigin, ()> {
159 Ok(Origin::get())
160 }
161}
162
163pub trait EnsureOriginWithArg<OuterOrigin, Argument> {
165 type Success;
167
168 fn ensure_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, BadOrigin> {
170 Self::try_origin(o, a).map_err(|_| BadOrigin)
171 }
172
173 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin>;
175
176 #[cfg(feature = "runtime-benchmarks")]
181 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()>;
182}
183
184#[macro_export]
190macro_rules! impl_ensure_origin_with_arg_ignoring_arg {
191 ( impl < { O: .., I: 'static, $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
192 impl_ensure_origin_with_arg_ignoring_arg! {
193 impl <{
194 O: $crate::traits::OriginTrait,
195 I: 'static,
196 $( $bound )*
197 }> EnsureOriginWithArg<O, $t_param> for $name {}
198 }
199 };
200 ( impl < { O: .. , $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
201 impl_ensure_origin_with_arg_ignoring_arg! {
202 impl <{
203 O: $crate::traits::OriginTrait,
204 $( $bound )*
205 }> EnsureOriginWithArg<O, $t_param> for $name {}
206 }
207 };
208 ( impl < { $( $bound:tt )* } > EnsureOriginWithArg<$o_param:ty, $t_param:ty> for $name:ty {} ) => {
209 impl < $( $bound )* > EnsureOriginWithArg<$o_param, $t_param> for $name {
210 type Success = <Self as EnsureOrigin<$o_param>>::Success;
211 fn try_origin(o: $o_param, _: &$t_param) -> Result<Self::Success, $o_param> {
212 <Self as EnsureOrigin<$o_param>>::try_origin(o)
213 }
214 #[cfg(feature = "runtime-benchmarks")]
215 fn try_successful_origin(_: &$t_param) -> Result<$o_param, ()> {
216 <Self as EnsureOrigin<$o_param>>::try_successful_origin()
217 }
218 }
219 }
220}
221
222pub struct NeverEnsureOrigin<Success>(core::marker::PhantomData<Success>);
224impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
225 type Success = Success;
226 fn try_origin(o: OO) -> Result<Success, OO> {
227 Err(o)
228 }
229 #[cfg(feature = "runtime-benchmarks")]
230 fn try_successful_origin() -> Result<OO, ()> {
231 Err(())
232 }
233}
234impl_ensure_origin_with_arg_ignoring_arg! {
235 impl<{ OO, Success, A }>
236 EnsureOriginWithArg<OO, A> for NeverEnsureOrigin<Success>
237 {}
238}
239
240pub struct AsEnsureOriginWithArg<EO>(core::marker::PhantomData<EO>);
241impl<OuterOrigin, Argument, EO: EnsureOrigin<OuterOrigin>>
242 EnsureOriginWithArg<OuterOrigin, Argument> for AsEnsureOriginWithArg<EO>
243{
244 type Success = EO::Success;
246
247 fn ensure_origin(o: OuterOrigin, _: &Argument) -> Result<Self::Success, BadOrigin> {
249 EO::ensure_origin(o)
250 }
251
252 fn try_origin(o: OuterOrigin, _: &Argument) -> Result<Self::Success, OuterOrigin> {
254 EO::try_origin(o)
255 }
256
257 #[cfg(feature = "runtime-benchmarks")]
261 fn try_successful_origin(_: &Argument) -> Result<OuterOrigin, ()> {
262 EO::try_successful_origin()
263 }
264}
265
266pub struct MapSuccess<Original, Mutator>(PhantomData<(Original, Mutator)>);
269impl<O, Original: EnsureOrigin<O>, Mutator: Morph<Original::Success>> EnsureOrigin<O>
270 for MapSuccess<Original, Mutator>
271{
272 type Success = Mutator::Outcome;
273 fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
274 Ok(Mutator::morph(Original::try_origin(o)?))
275 }
276 #[cfg(feature = "runtime-benchmarks")]
277 fn try_successful_origin() -> Result<O, ()> {
278 Original::try_successful_origin()
279 }
280}
281impl<O, Original: EnsureOriginWithArg<O, A>, Mutator: Morph<Original::Success>, A>
282 EnsureOriginWithArg<O, A> for MapSuccess<Original, Mutator>
283{
284 type Success = Mutator::Outcome;
285 fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
286 Ok(Mutator::morph(Original::try_origin(o, a)?))
287 }
288 #[cfg(feature = "runtime-benchmarks")]
289 fn try_successful_origin(a: &A) -> Result<O, ()> {
290 Original::try_successful_origin(a)
291 }
292}
293
294pub struct TryMapSuccess<Orig, Mutator>(PhantomData<(Orig, Mutator)>);
301impl<O: Clone, Original: EnsureOrigin<O>, Mutator: TryMorph<Original::Success>> EnsureOrigin<O>
302 for TryMapSuccess<Original, Mutator>
303{
304 type Success = Mutator::Outcome;
305 fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
306 let orig = o.clone();
307 Mutator::try_morph(Original::try_origin(o)?).map_err(|()| orig)
308 }
309 #[cfg(feature = "runtime-benchmarks")]
310 fn try_successful_origin() -> Result<O, ()> {
311 Original::try_successful_origin()
312 }
313}
314impl<O: Clone, Original: EnsureOriginWithArg<O, A>, Mutator: TryMorph<Original::Success>, A>
315 EnsureOriginWithArg<O, A> for TryMapSuccess<Original, Mutator>
316{
317 type Success = Mutator::Outcome;
318 fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
319 let orig = o.clone();
320 Mutator::try_morph(Original::try_origin(o, a)?).map_err(|()| orig)
321 }
322 #[cfg(feature = "runtime-benchmarks")]
323 fn try_successful_origin(a: &A) -> Result<O, ()> {
324 Original::try_successful_origin(a)
325 }
326}
327
328pub struct TryWithMorphedArg<O, A, Morph, Inner, Success>(
329 PhantomData<(O, A, Morph, Inner, Success)>,
330);
331impl<
332 O,
333 A,
334 Morph: for<'a> TryMorph<&'a A>,
335 Inner: for<'a> EnsureOriginWithArg<O, <Morph as TryMorph<&'a A>>::Outcome, Success = Success>,
336 Success,
337 > EnsureOriginWithArg<O, A> for TryWithMorphedArg<O, A, Morph, Inner, Success>
338{
339 type Success = Success;
340 fn try_origin(o: O, a: &A) -> Result<Success, O> {
341 match Morph::try_morph(a) {
342 Ok(x) => Inner::try_origin(o, &x),
343 _ => return Err(o),
344 }
345 }
346 #[cfg(feature = "runtime-benchmarks")]
347 fn try_successful_origin(a: &A) -> Result<O, ()> {
348 Inner::try_successful_origin(&Morph::try_morph(a).map_err(|_| ())?)
349 }
350}
351
352pub struct EitherOfDiverse<L, R>(core::marker::PhantomData<(L, R)>);
359impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
360 EnsureOrigin<OuterOrigin> for EitherOfDiverse<L, R>
361{
362 type Success = Either<L::Success, R::Success>;
363 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
364 L::try_origin(o)
365 .map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o)))
366 }
367
368 #[cfg(feature = "runtime-benchmarks")]
369 fn try_successful_origin() -> Result<OuterOrigin, ()> {
370 L::try_successful_origin().or_else(|()| R::try_successful_origin())
371 }
372}
373impl<
374 OuterOrigin,
375 L: EnsureOriginWithArg<OuterOrigin, Argument>,
376 R: EnsureOriginWithArg<OuterOrigin, Argument>,
377 Argument,
378 > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOfDiverse<L, R>
379{
380 type Success = Either<L::Success, R::Success>;
381 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
382 L::try_origin(o, a)
383 .map_or_else(|o| R::try_origin(o, a).map(Either::Right), |o| Ok(Either::Left(o)))
384 }
385
386 #[cfg(feature = "runtime-benchmarks")]
387 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
388 L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
389 }
390}
391
392#[deprecated = "Use `EitherOfDiverse` instead"]
399pub type EnsureOneOf<L, R> = EitherOfDiverse<L, R>;
400
401pub struct EitherOf<L, R>(core::marker::PhantomData<(L, R)>);
408impl<
409 OuterOrigin,
410 L: EnsureOrigin<OuterOrigin>,
411 R: EnsureOrigin<OuterOrigin, Success = L::Success>,
412 > EnsureOrigin<OuterOrigin> for EitherOf<L, R>
413{
414 type Success = L::Success;
415 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
416 L::try_origin(o).or_else(|o| R::try_origin(o))
417 }
418
419 #[cfg(feature = "runtime-benchmarks")]
420 fn try_successful_origin() -> Result<OuterOrigin, ()> {
421 L::try_successful_origin().or_else(|()| R::try_successful_origin())
422 }
423}
424impl<
425 OuterOrigin,
426 L: EnsureOriginWithArg<OuterOrigin, Argument>,
427 R: EnsureOriginWithArg<OuterOrigin, Argument, Success = L::Success>,
428 Argument,
429 > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOf<L, R>
430{
431 type Success = L::Success;
432 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
433 L::try_origin(o, a).or_else(|o| R::try_origin(o, a))
434 }
435
436 #[cfg(feature = "runtime-benchmarks")]
437 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
438 L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
439 }
440}
441
442pub trait UnfilteredDispatchable {
447 type RuntimeOrigin;
449
450 fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo;
452}
453
454pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId>> {
459 fn into_system(self) -> Option<RawOrigin<AccountId>>;
461
462 fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>;
464
465 fn as_signed(&self) -> Option<&AccountId> {
467 self.as_system_ref().and_then(RawOrigin::as_signed)
468 }
469
470 fn is_root(&self) -> bool {
472 self.as_system_ref().map_or(false, RawOrigin::is_root)
473 }
474
475 fn is_none(&self) -> bool {
477 self.as_system_ref().map_or(false, RawOrigin::is_none)
478 }
479}
480
481pub trait OriginTrait: Sized {
483 type Call;
485
486 type PalletsOrigin: Send + Sync + Into<Self> + CallerTrait<Self::AccountId> + MaxEncodedLen;
488
489 type AccountId;
491
492 fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static);
494
495 fn reset_filter(&mut self);
497
498 fn set_caller_from(&mut self, other: impl Into<Self>);
500
501 fn set_caller(&mut self, caller: Self::PalletsOrigin);
503
504 fn set_caller_from_signed(&mut self, caller_account: Self::AccountId) {
506 self.set_caller(Self::PalletsOrigin::from(RawOrigin::Signed(caller_account)))
507 }
508
509 fn filter_call(&self, call: &Self::Call) -> bool;
514
515 fn caller(&self) -> &Self::PalletsOrigin;
517
518 fn into_caller(self) -> Self::PalletsOrigin;
520
521 fn try_with_caller<R>(
523 self,
524 f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
525 ) -> Result<R, Self>;
526
527 fn none() -> Self;
529
530 fn root() -> Self;
532
533 fn signed(by: Self::AccountId) -> Self;
535
536 #[deprecated = "Use `into_signer` instead"]
538 fn as_signed(self) -> Option<Self::AccountId> {
539 self.into_signer()
540 }
541
542 fn into_signer(self) -> Option<Self::AccountId> {
544 self.into_caller().into_system().and_then(|s| {
545 if let RawOrigin::Signed(who) = s {
546 Some(who)
547 } else {
548 None
549 }
550 })
551 }
552
553 fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
555 self.caller().as_system_ref()
556 }
557
558 fn as_signer(&self) -> Option<&Self::AccountId> {
560 self.caller().as_system_ref().and_then(|s| {
561 if let RawOrigin::Signed(ref who) = s {
562 Some(who)
563 } else {
564 None
565 }
566 })
567 }
568}
569
570pub trait Authorize {
578 fn authorize(
585 &self,
586 source: TransactionSource,
587 ) -> Option<Result<(ValidTransaction, Weight), TransactionValidityError>>;
588
589 fn weight_of_authorize(&self) -> Weight;
591}
592
593#[cfg(test)]
594mod tests {
595 use super::*;
596 use crate::traits::{ConstBool, ConstU8, TypedGet};
597 use std::marker::PhantomData;
598
599 struct EnsureSuccess<V>(PhantomData<V>);
600 struct EnsureFail<T>(PhantomData<T>);
601
602 impl<V: TypedGet> EnsureOrigin<()> for EnsureSuccess<V> {
603 type Success = V::Type;
604 fn try_origin(_: ()) -> Result<Self::Success, ()> {
605 Ok(V::get())
606 }
607 #[cfg(feature = "runtime-benchmarks")]
608 fn try_successful_origin() -> Result<(), ()> {
609 Ok(())
610 }
611 }
612
613 impl<T> EnsureOrigin<()> for EnsureFail<T> {
614 type Success = T;
615 fn try_origin(_: ()) -> Result<Self::Success, ()> {
616 Err(())
617 }
618 #[cfg(feature = "runtime-benchmarks")]
619 fn try_successful_origin() -> Result<(), ()> {
620 Err(())
621 }
622 }
623
624 #[test]
625 fn either_of_diverse_works() {
626 assert_eq!(
627 EitherOfDiverse::<
628 EnsureSuccess<ConstBool<true>>,
629 EnsureSuccess<ConstU8<0>>,
630 >::try_origin(()).unwrap().left(),
631 Some(true)
632 );
633 assert_eq!(
634 EitherOfDiverse::<EnsureSuccess<ConstBool<true>>, EnsureFail<u8>>::try_origin(())
635 .unwrap()
636 .left(),
637 Some(true)
638 );
639 assert_eq!(
640 EitherOfDiverse::<EnsureFail<bool>, EnsureSuccess<ConstU8<0>>>::try_origin(())
641 .unwrap()
642 .right(),
643 Some(0u8)
644 );
645 assert!(EitherOfDiverse::<EnsureFail<bool>, EnsureFail<u8>>::try_origin(()).is_err());
646 }
647
648 #[test]
649 fn either_of_works() {
650 assert_eq!(
651 EitherOf::<
652 EnsureSuccess<ConstBool<true>>,
653 EnsureSuccess<ConstBool<false>>,
654 >::try_origin(()).unwrap(),
655 true
656 );
657 assert_eq!(
658 EitherOf::<EnsureSuccess<ConstBool<true>>, EnsureFail<bool>>::try_origin(()).unwrap(),
659 true
660 );
661 assert_eq!(
662 EitherOf::<EnsureFail<bool>, EnsureSuccess<ConstBool<false>>>::try_origin(()).unwrap(),
663 false
664 );
665 assert!(EitherOf::<EnsureFail<bool>, EnsureFail<bool>>::try_origin(()).is_err());
666 }
667}