1use crate::dispatch::{DispatchResultWithPostInfo, Parameter, RawOrigin};
10use codec::MaxEncodedLen;
11use core::{cmp::Ordering, marker::PhantomData};
12use subsoil::runtime::{
13 traits::{BadOrigin, Get, Member, Morph, TryMorph},
14 transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction},
15 Either,
16};
17use subsoil::weights::Weight;
18
19use super::misc;
20
21pub trait EnsureOrigin<OuterOrigin> {
23 type Success;
25
26 fn ensure_origin(o: OuterOrigin) -> Result<Self::Success, BadOrigin> {
28 Self::try_origin(o).map_err(|_| BadOrigin)
29 }
30
31 fn ensure_origin_or_root(o: OuterOrigin) -> Result<Option<Self::Success>, BadOrigin>
34 where
35 OuterOrigin: OriginTrait,
36 {
37 if o.caller().is_root() {
38 return Ok(None);
39 } else {
40 Self::ensure_origin(o).map(Some)
41 }
42 }
43
44 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin>;
46
47 fn try_origin_or_root(o: OuterOrigin) -> Result<Option<Self::Success>, OuterOrigin>
50 where
51 OuterOrigin: OriginTrait,
52 {
53 if o.caller().is_root() {
54 return Ok(None);
55 } else {
56 Self::try_origin(o).map(Some)
57 }
58 }
59
60 #[cfg(feature = "runtime-benchmarks")]
65 fn try_successful_origin() -> Result<OuterOrigin, ()>;
66}
67
68pub struct EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>(
118 core::marker::PhantomData<(Origin, PrivilegeCmp)>,
119);
120
121impl<OuterOrigin, Origin, PrivilegeCmp> EnsureOrigin<OuterOrigin>
122 for EnsureOriginEqualOrHigherPrivilege<Origin, PrivilegeCmp>
123where
124 Origin: Get<OuterOrigin>,
125 OuterOrigin: Eq,
126 PrivilegeCmp: misc::PrivilegeCmp<OuterOrigin>,
127{
128 type Success = ();
129
130 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
131 let expected_origin = Origin::get();
132
133 if o == expected_origin {
135 return Ok(());
136 }
137
138 let cmp = PrivilegeCmp::cmp_privilege(&o, &expected_origin);
139
140 match cmp {
141 Some(Ordering::Equal) | Some(Ordering::Greater) => Ok(()),
142 None | Some(Ordering::Less) => Err(o),
143 }
144 }
145
146 #[cfg(feature = "runtime-benchmarks")]
147 fn try_successful_origin() -> Result<OuterOrigin, ()> {
148 Ok(Origin::get())
149 }
150}
151
152pub trait EnsureOriginWithArg<OuterOrigin, Argument> {
154 type Success;
156
157 fn ensure_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, BadOrigin> {
159 Self::try_origin(o, a).map_err(|_| BadOrigin)
160 }
161
162 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin>;
164
165 #[cfg(feature = "runtime-benchmarks")]
170 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()>;
171}
172
173#[macro_export]
179macro_rules! impl_ensure_origin_with_arg_ignoring_arg {
180 ( impl < { O: .., I: 'static, $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
181 impl_ensure_origin_with_arg_ignoring_arg! {
182 impl <{
183 O: $crate::traits::OriginTrait,
184 I: 'static,
185 $( $bound )*
186 }> EnsureOriginWithArg<O, $t_param> for $name {}
187 }
188 };
189 ( impl < { O: .. , $( $bound:tt )* }> EnsureOriginWithArg<O, $t_param:ty> for $name:ty {} ) => {
190 impl_ensure_origin_with_arg_ignoring_arg! {
191 impl <{
192 O: $crate::traits::OriginTrait,
193 $( $bound )*
194 }> EnsureOriginWithArg<O, $t_param> for $name {}
195 }
196 };
197 ( impl < { $( $bound:tt )* } > EnsureOriginWithArg<$o_param:ty, $t_param:ty> for $name:ty {} ) => {
198 impl < $( $bound )* > EnsureOriginWithArg<$o_param, $t_param> for $name {
199 type Success = <Self as EnsureOrigin<$o_param>>::Success;
200 fn try_origin(o: $o_param, _: &$t_param) -> Result<Self::Success, $o_param> {
201 <Self as EnsureOrigin<$o_param>>::try_origin(o)
202 }
203 #[cfg(feature = "runtime-benchmarks")]
204 fn try_successful_origin(_: &$t_param) -> Result<$o_param, ()> {
205 <Self as EnsureOrigin<$o_param>>::try_successful_origin()
206 }
207 }
208 }
209}
210
211pub struct NeverEnsureOrigin<Success>(core::marker::PhantomData<Success>);
213impl<OO, Success> EnsureOrigin<OO> for NeverEnsureOrigin<Success> {
214 type Success = Success;
215 fn try_origin(o: OO) -> Result<Success, OO> {
216 Err(o)
217 }
218 #[cfg(feature = "runtime-benchmarks")]
219 fn try_successful_origin() -> Result<OO, ()> {
220 Err(())
221 }
222}
223impl_ensure_origin_with_arg_ignoring_arg! {
224 impl<{ OO, Success, A }>
225 EnsureOriginWithArg<OO, A> for NeverEnsureOrigin<Success>
226 {}
227}
228
229pub struct AsEnsureOriginWithArg<EO>(core::marker::PhantomData<EO>);
230impl<OuterOrigin, Argument, EO: EnsureOrigin<OuterOrigin>>
231 EnsureOriginWithArg<OuterOrigin, Argument> for AsEnsureOriginWithArg<EO>
232{
233 type Success = EO::Success;
235
236 fn ensure_origin(o: OuterOrigin, _: &Argument) -> Result<Self::Success, BadOrigin> {
238 EO::ensure_origin(o)
239 }
240
241 fn try_origin(o: OuterOrigin, _: &Argument) -> Result<Self::Success, OuterOrigin> {
243 EO::try_origin(o)
244 }
245
246 #[cfg(feature = "runtime-benchmarks")]
250 fn try_successful_origin(_: &Argument) -> Result<OuterOrigin, ()> {
251 EO::try_successful_origin()
252 }
253}
254
255pub struct MapSuccess<Original, Mutator>(PhantomData<(Original, Mutator)>);
258impl<O, Original: EnsureOrigin<O>, Mutator: Morph<Original::Success>> EnsureOrigin<O>
259 for MapSuccess<Original, Mutator>
260{
261 type Success = Mutator::Outcome;
262 fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
263 Ok(Mutator::morph(Original::try_origin(o)?))
264 }
265 #[cfg(feature = "runtime-benchmarks")]
266 fn try_successful_origin() -> Result<O, ()> {
267 Original::try_successful_origin()
268 }
269}
270impl<O, Original: EnsureOriginWithArg<O, A>, Mutator: Morph<Original::Success>, A>
271 EnsureOriginWithArg<O, A> for MapSuccess<Original, Mutator>
272{
273 type Success = Mutator::Outcome;
274 fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
275 Ok(Mutator::morph(Original::try_origin(o, a)?))
276 }
277 #[cfg(feature = "runtime-benchmarks")]
278 fn try_successful_origin(a: &A) -> Result<O, ()> {
279 Original::try_successful_origin(a)
280 }
281}
282
283pub struct TryMapSuccess<Orig, Mutator>(PhantomData<(Orig, Mutator)>);
290impl<O: Clone, Original: EnsureOrigin<O>, Mutator: TryMorph<Original::Success>> EnsureOrigin<O>
291 for TryMapSuccess<Original, Mutator>
292{
293 type Success = Mutator::Outcome;
294 fn try_origin(o: O) -> Result<Mutator::Outcome, O> {
295 let orig = o.clone();
296 Mutator::try_morph(Original::try_origin(o)?).map_err(|()| orig)
297 }
298 #[cfg(feature = "runtime-benchmarks")]
299 fn try_successful_origin() -> Result<O, ()> {
300 Original::try_successful_origin()
301 }
302}
303impl<O: Clone, Original: EnsureOriginWithArg<O, A>, Mutator: TryMorph<Original::Success>, A>
304 EnsureOriginWithArg<O, A> for TryMapSuccess<Original, Mutator>
305{
306 type Success = Mutator::Outcome;
307 fn try_origin(o: O, a: &A) -> Result<Mutator::Outcome, O> {
308 let orig = o.clone();
309 Mutator::try_morph(Original::try_origin(o, a)?).map_err(|()| orig)
310 }
311 #[cfg(feature = "runtime-benchmarks")]
312 fn try_successful_origin(a: &A) -> Result<O, ()> {
313 Original::try_successful_origin(a)
314 }
315}
316
317pub struct TryWithMorphedArg<O, A, Morph, Inner, Success>(
318 PhantomData<(O, A, Morph, Inner, Success)>,
319);
320impl<
321 O,
322 A,
323 Morph: for<'a> TryMorph<&'a A>,
324 Inner: for<'a> EnsureOriginWithArg<O, <Morph as TryMorph<&'a A>>::Outcome, Success = Success>,
325 Success,
326 > EnsureOriginWithArg<O, A> for TryWithMorphedArg<O, A, Morph, Inner, Success>
327{
328 type Success = Success;
329 fn try_origin(o: O, a: &A) -> Result<Success, O> {
330 match Morph::try_morph(a) {
331 Ok(x) => Inner::try_origin(o, &x),
332 _ => return Err(o),
333 }
334 }
335 #[cfg(feature = "runtime-benchmarks")]
336 fn try_successful_origin(a: &A) -> Result<O, ()> {
337 Inner::try_successful_origin(&Morph::try_morph(a).map_err(|_| ())?)
338 }
339}
340
341pub struct EitherOfDiverse<L, R>(core::marker::PhantomData<(L, R)>);
348impl<OuterOrigin, L: EnsureOrigin<OuterOrigin>, R: EnsureOrigin<OuterOrigin>>
349 EnsureOrigin<OuterOrigin> for EitherOfDiverse<L, R>
350{
351 type Success = Either<L::Success, R::Success>;
352 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
353 L::try_origin(o)
354 .map_or_else(|o| R::try_origin(o).map(Either::Right), |o| Ok(Either::Left(o)))
355 }
356
357 #[cfg(feature = "runtime-benchmarks")]
358 fn try_successful_origin() -> Result<OuterOrigin, ()> {
359 L::try_successful_origin().or_else(|()| R::try_successful_origin())
360 }
361}
362impl<
363 OuterOrigin,
364 L: EnsureOriginWithArg<OuterOrigin, Argument>,
365 R: EnsureOriginWithArg<OuterOrigin, Argument>,
366 Argument,
367 > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOfDiverse<L, R>
368{
369 type Success = Either<L::Success, R::Success>;
370 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
371 L::try_origin(o, a)
372 .map_or_else(|o| R::try_origin(o, a).map(Either::Right), |o| Ok(Either::Left(o)))
373 }
374
375 #[cfg(feature = "runtime-benchmarks")]
376 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
377 L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
378 }
379}
380
381#[deprecated = "Use `EitherOfDiverse` instead"]
388pub type EnsureOneOf<L, R> = EitherOfDiverse<L, R>;
389
390pub struct EitherOf<L, R>(core::marker::PhantomData<(L, R)>);
397impl<
398 OuterOrigin,
399 L: EnsureOrigin<OuterOrigin>,
400 R: EnsureOrigin<OuterOrigin, Success = L::Success>,
401 > EnsureOrigin<OuterOrigin> for EitherOf<L, R>
402{
403 type Success = L::Success;
404 fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
405 L::try_origin(o).or_else(|o| R::try_origin(o))
406 }
407
408 #[cfg(feature = "runtime-benchmarks")]
409 fn try_successful_origin() -> Result<OuterOrigin, ()> {
410 L::try_successful_origin().or_else(|()| R::try_successful_origin())
411 }
412}
413impl<
414 OuterOrigin,
415 L: EnsureOriginWithArg<OuterOrigin, Argument>,
416 R: EnsureOriginWithArg<OuterOrigin, Argument, Success = L::Success>,
417 Argument,
418 > EnsureOriginWithArg<OuterOrigin, Argument> for EitherOf<L, R>
419{
420 type Success = L::Success;
421 fn try_origin(o: OuterOrigin, a: &Argument) -> Result<Self::Success, OuterOrigin> {
422 L::try_origin(o, a).or_else(|o| R::try_origin(o, a))
423 }
424
425 #[cfg(feature = "runtime-benchmarks")]
426 fn try_successful_origin(a: &Argument) -> Result<OuterOrigin, ()> {
427 L::try_successful_origin(a).or_else(|()| R::try_successful_origin(a))
428 }
429}
430
431pub trait UnfilteredDispatchable {
436 type RuntimeOrigin;
438
439 fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo;
441}
442
443pub trait CallerTrait<AccountId>: Parameter + Member + From<RawOrigin<AccountId>> {
448 fn into_system(self) -> Option<RawOrigin<AccountId>>;
450
451 fn as_system_ref(&self) -> Option<&RawOrigin<AccountId>>;
453
454 fn as_signed(&self) -> Option<&AccountId> {
456 self.as_system_ref().and_then(RawOrigin::as_signed)
457 }
458
459 fn is_root(&self) -> bool {
461 self.as_system_ref().map_or(false, RawOrigin::is_root)
462 }
463
464 fn is_none(&self) -> bool {
466 self.as_system_ref().map_or(false, RawOrigin::is_none)
467 }
468}
469
470pub trait OriginTrait: Sized {
472 type Call;
474
475 type PalletsOrigin: Send + Sync + Into<Self> + CallerTrait<Self::AccountId> + MaxEncodedLen;
477
478 type AccountId;
480
481 fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static);
483
484 fn reset_filter(&mut self);
486
487 fn set_caller_from(&mut self, other: impl Into<Self>);
489
490 fn set_caller(&mut self, caller: Self::PalletsOrigin);
492
493 fn set_caller_from_signed(&mut self, caller_account: Self::AccountId) {
495 self.set_caller(Self::PalletsOrigin::from(RawOrigin::Signed(caller_account)))
496 }
497
498 fn filter_call(&self, call: &Self::Call) -> bool;
503
504 fn caller(&self) -> &Self::PalletsOrigin;
506
507 fn into_caller(self) -> Self::PalletsOrigin;
509
510 fn try_with_caller<R>(
512 self,
513 f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
514 ) -> Result<R, Self>;
515
516 fn none() -> Self;
518
519 fn root() -> Self;
521
522 fn signed(by: Self::AccountId) -> Self;
524
525 #[deprecated = "Use `into_signer` instead"]
527 fn as_signed(self) -> Option<Self::AccountId> {
528 self.into_signer()
529 }
530
531 fn into_signer(self) -> Option<Self::AccountId> {
533 self.into_caller().into_system().and_then(|s| {
534 if let RawOrigin::Signed(who) = s {
535 Some(who)
536 } else {
537 None
538 }
539 })
540 }
541
542 fn as_system_ref(&self) -> Option<&RawOrigin<Self::AccountId>> {
544 self.caller().as_system_ref()
545 }
546
547 fn as_signer(&self) -> Option<&Self::AccountId> {
549 self.caller().as_system_ref().and_then(|s| {
550 if let RawOrigin::Signed(ref who) = s {
551 Some(who)
552 } else {
553 None
554 }
555 })
556 }
557}
558
559pub trait Authorize {
567 fn authorize(
574 &self,
575 source: TransactionSource,
576 ) -> Option<Result<(ValidTransaction, Weight), TransactionValidityError>>;
577
578 fn weight_of_authorize(&self) -> Weight;
580}
581
582#[cfg(test)]
583mod tests {
584 use super::*;
585 use crate::traits::{ConstBool, ConstU8, TypedGet};
586 use std::marker::PhantomData;
587
588 struct EnsureSuccess<V>(PhantomData<V>);
589 struct EnsureFail<T>(PhantomData<T>);
590
591 impl<V: TypedGet> EnsureOrigin<()> for EnsureSuccess<V> {
592 type Success = V::Type;
593 fn try_origin(_: ()) -> Result<Self::Success, ()> {
594 Ok(V::get())
595 }
596 #[cfg(feature = "runtime-benchmarks")]
597 fn try_successful_origin() -> Result<(), ()> {
598 Ok(())
599 }
600 }
601
602 impl<T> EnsureOrigin<()> for EnsureFail<T> {
603 type Success = T;
604 fn try_origin(_: ()) -> Result<Self::Success, ()> {
605 Err(())
606 }
607 #[cfg(feature = "runtime-benchmarks")]
608 fn try_successful_origin() -> Result<(), ()> {
609 Err(())
610 }
611 }
612
613 #[test]
614 fn either_of_diverse_works() {
615 assert_eq!(
616 EitherOfDiverse::<
617 EnsureSuccess<ConstBool<true>>,
618 EnsureSuccess<ConstU8<0>>,
619 >::try_origin(()).unwrap().left(),
620 Some(true)
621 );
622 assert_eq!(
623 EitherOfDiverse::<EnsureSuccess<ConstBool<true>>, EnsureFail<u8>>::try_origin(())
624 .unwrap()
625 .left(),
626 Some(true)
627 );
628 assert_eq!(
629 EitherOfDiverse::<EnsureFail<bool>, EnsureSuccess<ConstU8<0>>>::try_origin(())
630 .unwrap()
631 .right(),
632 Some(0u8)
633 );
634 assert!(EitherOfDiverse::<EnsureFail<bool>, EnsureFail<u8>>::try_origin(()).is_err());
635 }
636
637 #[test]
638 fn either_of_works() {
639 assert_eq!(
640 EitherOf::<
641 EnsureSuccess<ConstBool<true>>,
642 EnsureSuccess<ConstBool<false>>,
643 >::try_origin(()).unwrap(),
644 true
645 );
646 assert_eq!(
647 EitherOf::<EnsureSuccess<ConstBool<true>>, EnsureFail<bool>>::try_origin(()).unwrap(),
648 true
649 );
650 assert_eq!(
651 EitherOf::<EnsureFail<bool>, EnsureSuccess<ConstBool<false>>>::try_origin(()).unwrap(),
652 false
653 );
654 assert!(EitherOf::<EnsureFail<bool>, EnsureFail<bool>>::try_origin(()).is_err());
655 }
656}