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 Either,
26};
27
28use super::misc;
29
30pub trait EnsureOrigin<OuterOrigin> {
32 type Success;
34
35 fn ensure_origin(o: OuterOrigin) -> Result<Self::Success, BadOrigin> {
37 Self::try_origin(o).map_err(|_| BadOrigin)
38 }
39
40 fn ensure_origin_or_root(o: OuterOrigin) -> Result<Option<Self::Success>, BadOrigin>
43 where
44 OuterOrigin: OriginTrait,
45 {
46 if o.caller().is_root() {
47 return Ok(None)
48 } else {
49 Self::ensure_origin(o).map(Some)
50 }
51 }
52
53 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin>;
55
56 fn try_origin_or_root(o: OuterOrigin) -> Result<Option<Self::Success>, OuterOrigin>
59 where
60 OuterOrigin: OriginTrait,
61 {
62 if o.caller().is_root() {
63 return Ok(None)
64 } else {
65 Self::try_origin(o).map(Some)
66 }
67 }
68
69 #[cfg(feature = "runtime-benchmarks")]
74 fn try_successful_origin() -> Result<OuterOrigin, ()>;
75}
76
77pub struct EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>(
127 core::marker::PhantomData<(Origin, PrivilegeCmp)>,
128);
129
130impl<OuterOrigin, Origin, PrivilegeCmp> EnsureOrigin<OuterOrigin>
131 for EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>
132where
133 Origin: Get<OuterOrigin>,
134 OuterOrigin: Eq,
135 PrivilegeCmp: misc::PrivilegeCmp<OuterOrigin>,
136{
137 type Success = ();
138
139 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
140 let expected_origin = Origin::get();
141
142 if o == expected_origin {
144 return Ok(())
145 }
146
147 let cmp = PrivilegeCmp::cmp_privilege(&o, &expected_origin);
148
149 match cmp {
150 Some(Ordering::Equal) | Some(Ordering::Greater) => Ok(()),
151 None | Some(Ordering::Less) => Err(o),
152 }
153 }
154
155 #[cfg(feature = "runtime-benchmarks")]
156 fn try_successful_origin() -> Result<OuterOrigin, ()> {
157 Ok(Origin::get())
158 }
159}
160
161pub trait EnsureOriginWithArg<OuterOrigin, Argument> {
163 type Success;
165
166 fn ensure_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, BadOrigin> {
168 Self::try_origin(o, a).map_err(|_| BadOrigin)
169 }
170
171 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin>;
173
174 #[cfg(feature = "runtime-benchmarks")]
179 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()>;
180}
181
182#[macro_export]
188macro_rules! impl_ensure_origin_with_arg_ignoring_arg {
189 ( impl < { O: .., I: 'static, $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
190 impl_ensure_origin_with_arg_ignoring_arg! {
191 impl <{
192 O: Into<Result<RawOrigin<AccountId, I>, O>> + From<RawOrigin<AccountId, I>>,
193 I: 'static,
194 $( $bound )*
195 }> EnsureOriginWithArg<O, $t_param> for $name {}
196 }
197 };
198 ( impl < { O: .. , $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
199 impl_ensure_origin_with_arg_ignoring_arg! {
200 impl <{
201 O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>,
202 $( $bound )*
203 }> EnsureOriginWithArg<O, $t_param> for $name {}
204 }
205 };
206 ( impl < { $( $bound:tt )* } > EnsureOriginWithArg<$o_param:ty, $t_param:ty> for $name:ty {} ) => {
207 impl < $( $bound )* > EnsureOriginWithArg<$o_param, $t_param> for $name {
208 type Success = <Self as EnsureOrigin<$o_param>>::Success;
209 fn try_origin(o: $o_param, _: &$t_param) -> Result<Self::Success, $o_param> {
210 <Self as EnsureOrigin<$o_param>>::try_origin(o)
211 }
212 #[cfg(feature = "runtime-benchmarks")]
213 fn try_successful_origin(_: &$t_param) -> Result<$o_param, ()> {
214 <Self as EnsureOrigin<$o_param>>::try_successful_origin()
215 }
216 }
217 }
218}
219
220pub struct NeverEnsureOrigin<Success>(core::marker::PhantomData<Success>);
222impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
223 type Success = Success;
224 fn try_origin(o: OO) -> Result<Success, OO> {
225 Err(o)
226 }
227 #[cfg(feature = "runtime-benchmarks")]
228 fn try_successful_origin() -> Result<OO, ()> {
229 Err(())
230 }
231}
232impl_ensure_origin_with_arg_ignoring_arg! {
233 impl<{ OO, Success, A }>
234 EnsureOriginWithArg<OO, A> for NeverEnsureOrigin<Success>
235 {}
236}
237
238pub struct AsEnsureOriginWithArg<EO>(core::marker::PhantomData<EO>);
239impl<OuterOrigin, Argument, EO: EnsureOrigin<OuterOrigin>>
240 EnsureOriginWithArg<OuterOrigin, Argument> for AsEnsureOriginWithArg<EO>
241{
242 type Success = EO::Success;
244
245 fn ensure_origin(o: OuterOrigin, _: &Argument) -> Result<Self::Success, BadOrigin> {
247 EO::ensure_origin(o)
248 }
249
250 fn try_origin(o: OuterOrigin, _: &Argument) -> Result<Self::Success, OuterOrigin> {
252 EO::try_origin(o)
253 }
254
255 #[cfg(feature = "runtime-benchmarks")]
259 fn try_successful_origin(_: &Argument) -> Result<OuterOrigin, ()> {
260 EO::try_successful_origin()
261 }
262}
263
264pub struct MapSuccess<Original, Mutator>(PhantomData<(Original, Mutator)>);
267impl<O, Original: EnsureOrigin<O>, Mutator: Morph<Original::Success>> EnsureOrigin<O>
268 for MapSuccess<Original, Mutator>
269{
270 type Success = Mutator::Outcome;
271 fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
272 Ok(Mutator::morph(Original::try_origin(o)?))
273 }
274 #[cfg(feature = "runtime-benchmarks")]
275 fn try_successful_origin() -> Result<O, ()> {
276 Original::try_successful_origin()
277 }
278}
279impl<O, Original: EnsureOriginWithArg<O, A>, Mutator: Morph<Original::Success>, A>
280 EnsureOriginWithArg<O, A> for MapSuccess<Original, Mutator>
281{
282 type Success = Mutator::Outcome;
283 fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
284 Ok(Mutator::morph(Original::try_origin(o, a)?))
285 }
286 #[cfg(feature = "runtime-benchmarks")]
287 fn try_successful_origin(a: &A) -> Result<O, ()> {
288 Original::try_successful_origin(a)
289 }
290}
291
292pub struct TryMapSuccess<Orig, Mutator>(PhantomData<(Orig, Mutator)>);
299impl<O: Clone, Original: EnsureOrigin<O>, Mutator: TryMorph<Original::Success>> EnsureOrigin<O>
300 for TryMapSuccess<Original, Mutator>
301{
302 type Success = Mutator::Outcome;
303 fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
304 let orig = o.clone();
305 Mutator::try_morph(Original::try_origin(o)?).map_err(|()| orig)
306 }
307 #[cfg(feature = "runtime-benchmarks")]
308 fn try_successful_origin() -> Result<O, ()> {
309 Original::try_successful_origin()
310 }
311}
312impl<O: Clone, Original: EnsureOriginWithArg<O, A>, Mutator: TryMorph<Original::Success>, A>
313 EnsureOriginWithArg<O, A> for TryMapSuccess<Original, Mutator>
314{
315 type Success = Mutator::Outcome;
316 fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
317 let orig = o.clone();
318 Mutator::try_morph(Original::try_origin(o, a)?).map_err(|()| orig)
319 }
320 #[cfg(feature = "runtime-benchmarks")]
321 fn try_successful_origin(a: &A) -> Result<O, ()> {
322 Original::try_successful_origin(a)
323 }
324}
325
326pub struct TryWithMorphedArg<O, A, Morph, Inner, Success>(
327 PhantomData<(O, A, Morph, Inner, Success)>,
328);
329impl<
330 O,
331 A,
332 Morph: for<'a> TryMorph<&'a A>,
333 Inner: for<'a> EnsureOriginWithArg<O, <Morph as TryMorph<&'a A>>::Outcome, Success = Success>,
334 Success,
335 > EnsureOriginWithArg<O, A> for TryWithMorphedArg<O, A, Morph, Inner, Success>
336{
337 type Success = Success;
338 fn try_origin(o: O, a: &A) -> Result<Success, O> {
339 match Morph::try_morph(a) {
340 Ok(x) => Inner::try_origin(o, &x),
341 _ => return Err(o),
342 }
343 }
344 #[cfg(feature = "runtime-benchmarks")]
345 fn try_successful_origin(a: &A) -> Result<O, ()> {
346 Inner::try_successful_origin(&Morph::try_morph(a).map_err(|_| ())?)
347 }
348}
349
350pub struct EitherOfDiverse<L, R>(core::marker::PhantomData<(L, R)>);
357impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
358 EnsureOrigin<OuterOrigin> for EitherOfDiverse<L, R>
359{
360 type Success = Either<L::Success, R::Success>;
361 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
362 L::try_origin(o)
363 .map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o)))
364 }
365
366 #[cfg(feature = "runtime-benchmarks")]
367 fn try_successful_origin() -> Result<OuterOrigin, ()> {
368 L::try_successful_origin().or_else(|()| R::try_successful_origin())
369 }
370}
371impl<
372 OuterOrigin,
373 L: EnsureOriginWithArg<OuterOrigin, Argument>,
374 R: EnsureOriginWithArg<OuterOrigin, Argument>,
375 Argument,
376 > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOfDiverse<L, R>
377{
378 type Success = Either<L::Success, R::Success>;
379 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
380 L::try_origin(o, a)
381 .map_or_else(|o| R::try_origin(o, a).map(Either::Right), |o| Ok(Either::Left(o)))
382 }
383
384 #[cfg(feature = "runtime-benchmarks")]
385 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
386 L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
387 }
388}
389
390#[deprecated = "Use `EitherOfDiverse` instead"]
397pub type EnsureOneOf<L, R> = EitherOfDiverse<L, R>;
398
399pub struct EitherOf<L, R>(core::marker::PhantomData<(L, R)>);
406impl<
407 OuterOrigin,
408 L: EnsureOrigin<OuterOrigin>,
409 R: EnsureOrigin<OuterOrigin, Success = L::Success>,
410 > EnsureOrigin<OuterOrigin> for EitherOf<L, R>
411{
412 type Success = L::Success;
413 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
414 L::try_origin(o).or_else(|o| R::try_origin(o))
415 }
416
417 #[cfg(feature = "runtime-benchmarks")]
418 fn try_successful_origin() -> Result<OuterOrigin, ()> {
419 L::try_successful_origin().or_else(|()| R::try_successful_origin())
420 }
421}
422impl<
423 OuterOrigin,
424 L: EnsureOriginWithArg<OuterOrigin, Argument>,
425 R: EnsureOriginWithArg<OuterOrigin, Argument, Success = L::Success>,
426 Argument,
427 > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOf<L, R>
428{
429 type Success = L::Success;
430 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
431 L::try_origin(o, a).or_else(|o| R::try_origin(o, a))
432 }
433
434 #[cfg(feature = "runtime-benchmarks")]
435 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
436 L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
437 }
438}
439
440pub trait UnfilteredDispatchable {
445 type RuntimeOrigin;
447
448 fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo;
450}
451
452pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId>> {
457 fn into_system(self) -> Option<RawOrigin<AccountId>>;
459
460 fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>;
462
463 fn as_signed(&self) -> Option<&AccountId> {
465 self.as_system_ref().and_then(RawOrigin::as_signed)
466 }
467
468 fn is_root(&self) -> bool {
470 self.as_system_ref().map_or(false, RawOrigin::is_root)
471 }
472
473 fn is_none(&self) -> bool {
475 self.as_system_ref().map_or(false, RawOrigin::is_none)
476 }
477}
478
479pub trait OriginTrait: Sized {
481 type Call;
483
484 type PalletsOrigin: Send + Sync + Into<Self> + CallerTrait<Self::AccountId> + MaxEncodedLen;
486
487 type AccountId;
489
490 fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static);
492
493 fn reset_filter(&mut self);
495
496 fn set_caller_from(&mut self, other: impl Into<Self>);
498
499 fn set_caller(&mut self, caller: Self::PalletsOrigin);
501
502 fn set_caller_from_signed(&mut self, caller_account: Self::AccountId) {
504 self.set_caller(Self::PalletsOrigin::from(RawOrigin::Signed(caller_account)))
505 }
506
507 fn filter_call(&self, call: &Self::Call) -> bool;
512
513 fn caller(&self) -> &Self::PalletsOrigin;
515
516 fn into_caller(self) -> Self::PalletsOrigin;
518
519 fn try_with_caller<R>(
521 self,
522 f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
523 ) -> Result<R, Self>;
524
525 fn none() -> Self;
527
528 fn root() -> Self;
530
531 fn signed(by: Self::AccountId) -> Self;
533
534 #[deprecated = "Use `into_signer` instead"]
536 fn as_signed(self) -> Option<Self::AccountId> {
537 self.into_signer()
538 }
539
540 fn into_signer(self) -> Option<Self::AccountId> {
542 self.into_caller().into_system().and_then(|s| {
543 if let RawOrigin::Signed(who) = s {
544 Some(who)
545 } else {
546 None
547 }
548 })
549 }
550
551 fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
553 self.caller().as_system_ref()
554 }
555
556 fn as_signer(&self) -> Option<&Self::AccountId> {
558 self.caller().as_system_ref().and_then(|s| {
559 if let RawOrigin::Signed(ref who) = s {
560 Some(who)
561 } else {
562 None
563 }
564 })
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571 use crate::traits::{ConstBool, ConstU8, TypedGet};
572 use std::marker::PhantomData;
573
574 struct EnsureSuccess<V>(PhantomData<V>);
575 struct EnsureFail<T>(PhantomData<T>);
576
577 impl<V: TypedGet> EnsureOrigin<()> for EnsureSuccess<V> {
578 type Success = V::Type;
579 fn try_origin(_: ()) -> Result<Self::Success, ()> {
580 Ok(V::get())
581 }
582 #[cfg(feature = "runtime-benchmarks")]
583 fn try_successful_origin() -> Result<(), ()> {
584 Ok(())
585 }
586 }
587
588 impl<T> EnsureOrigin<()> for EnsureFail<T> {
589 type Success = T;
590 fn try_origin(_: ()) -> Result<Self::Success, ()> {
591 Err(())
592 }
593 #[cfg(feature = "runtime-benchmarks")]
594 fn try_successful_origin() -> Result<(), ()> {
595 Err(())
596 }
597 }
598
599 #[test]
600 fn either_of_diverse_works() {
601 assert_eq!(
602 EitherOfDiverse::<
603 EnsureSuccess<ConstBool<true>>,
604 EnsureSuccess<ConstU8<0>>,
605 >::try_origin(()).unwrap().left(),
606 Some(true)
607 );
608 assert_eq!(
609 EitherOfDiverse::<EnsureSuccess<ConstBool<true>>, EnsureFail<u8>>::try_origin(())
610 .unwrap()
611 .left(),
612 Some(true)
613 );
614 assert_eq!(
615 EitherOfDiverse::<EnsureFail<bool>, EnsureSuccess<ConstU8<0>>>::try_origin(())
616 .unwrap()
617 .right(),
618 Some(0u8)
619 );
620 assert!(EitherOfDiverse::<EnsureFail<bool>, EnsureFail<u8>>::try_origin(()).is_err());
621 }
622
623 #[test]
624 fn either_of_works() {
625 assert_eq!(
626 EitherOf::<
627 EnsureSuccess<ConstBool<true>>,
628 EnsureSuccess<ConstBool<false>>,
629 >::try_origin(()).unwrap(),
630 true
631 );
632 assert_eq!(
633 EitherOf::<EnsureSuccess<ConstBool<true>>, EnsureFail<bool>>::try_origin(()).unwrap(),
634 true
635 );
636 assert_eq!(
637 EitherOf::<EnsureFail<bool>, EnsureSuccess<ConstBool<false>>>::try_origin(()).unwrap(),
638 false
639 );
640 assert!(EitherOf::<EnsureFail<bool>, EnsureFail<bool>>::try_origin(()).is_err());
641 }
642}