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: 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 filter_call(&self, call: &Self::Call) -> bool;
504
505 fn caller(&self) -> &Self::PalletsOrigin;
507
508 fn into_caller(self) -> Self::PalletsOrigin;
510
511 fn try_with_caller<R>(
513 self,
514 f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
515 ) -> Result<R, Self>;
516
517 fn none() -> Self;
519
520 fn root() -> Self;
522
523 fn signed(by: Self::AccountId) -> Self;
525
526 #[deprecated = "Use `into_signer` instead"]
528 fn as_signed(self) -> Option<Self::AccountId> {
529 self.into_signer()
530 }
531
532 fn into_signer(self) -> Option<Self::AccountId> {
534 self.into_caller().into_system().and_then(|s| {
535 if let RawOrigin::Signed(who) = s {
536 Some(who)
537 } else {
538 None
539 }
540 })
541 }
542
543 fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
545 self.caller().as_system_ref()
546 }
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552 use crate::traits::{ConstBool, ConstU8, TypedGet};
553 use std::marker::PhantomData;
554
555 struct EnsureSuccess<V>(PhantomData<V>);
556 struct EnsureFail<T>(PhantomData<T>);
557
558 impl<V: TypedGet> EnsureOrigin<()> for EnsureSuccess<V> {
559 type Success = V::Type;
560 fn try_origin(_: ()) -> Result<Self::Success, ()> {
561 Ok(V::get())
562 }
563 #[cfg(feature = "runtime-benchmarks")]
564 fn try_successful_origin() -> Result<(), ()> {
565 Ok(())
566 }
567 }
568
569 impl<T> EnsureOrigin<()> for EnsureFail<T> {
570 type Success = T;
571 fn try_origin(_: ()) -> Result<Self::Success, ()> {
572 Err(())
573 }
574 #[cfg(feature = "runtime-benchmarks")]
575 fn try_successful_origin() -> Result<(), ()> {
576 Err(())
577 }
578 }
579
580 #[test]
581 fn either_of_diverse_works() {
582 assert_eq!(
583 EitherOfDiverse::<
584 EnsureSuccess<ConstBool<true>>,
585 EnsureSuccess<ConstU8<0>>,
586 >::try_origin(()).unwrap().left(),
587 Some(true)
588 );
589 assert_eq!(
590 EitherOfDiverse::<EnsureSuccess<ConstBool<true>>, EnsureFail<u8>>::try_origin(())
591 .unwrap()
592 .left(),
593 Some(true)
594 );
595 assert_eq!(
596 EitherOfDiverse::<EnsureFail<bool>, EnsureSuccess<ConstU8<0>>>::try_origin(())
597 .unwrap()
598 .right(),
599 Some(0u8)
600 );
601 assert!(EitherOfDiverse::<EnsureFail<bool>, EnsureFail<u8>>::try_origin(()).is_err());
602 }
603
604 #[test]
605 fn either_of_works() {
606 assert_eq!(
607 EitherOf::<
608 EnsureSuccess<ConstBool<true>>,
609 EnsureSuccess<ConstBool<false>>,
610 >::try_origin(()).unwrap(),
611 true
612 );
613 assert_eq!(
614 EitherOf::<EnsureSuccess<ConstBool<true>>, EnsureFail<bool>>::try_origin(()).unwrap(),
615 true
616 );
617 assert_eq!(
618 EitherOf::<EnsureFail<bool>, EnsureSuccess<ConstBool<false>>>::try_origin(()).unwrap(),
619 false
620 );
621 assert!(EitherOf::<EnsureFail<bool>, EnsureFail<bool>>::try_origin(()).is_err());
622 }
623}