Skip to main content

pallet_domain_sudo/
lib.rs

1// Copyright (C) 2023 Subspace Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Pallet Domain sudo
17
18#![cfg_attr(not(feature = "std"), no_std)]
19
20#[cfg(not(feature = "std"))]
21extern crate alloc;
22
23pub use pallet::*;
24
25#[frame_support::pallet]
26mod pallet {
27    #[cfg(not(feature = "std"))]
28    use alloc::boxed::Box;
29    use frame_support::dispatch::{GetDispatchInfo, RawOrigin};
30    use frame_support::pallet_prelude::*;
31    use frame_support::traits::UnfilteredDispatchable;
32    use frame_system::ensure_none;
33    use frame_system::pallet_prelude::OriginFor;
34    use sp_domain_sudo::{INHERENT_IDENTIFIER, InherentError, InherentType, IntoRuntimeCall};
35
36    #[pallet::config]
37    pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
38        type RuntimeCall: Parameter
39            + UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
40            + GetDispatchInfo;
41        type IntoRuntimeCall: IntoRuntimeCall<<Self as Config>::RuntimeCall>;
42    }
43
44    #[pallet::event]
45    #[pallet::generate_deposit(pub (super) fn deposit_event)]
46    pub enum Event<T: Config> {
47        /// A sudo call just took place.
48        Sudid {
49            /// The result of the call made by the sudo user.
50            sudo_result: DispatchResult,
51        },
52    }
53
54    /// Pallet Domain Sudo
55    #[pallet::pallet]
56    #[pallet::without_storage_info]
57    pub struct Pallet<T>(_);
58
59    #[pallet::call]
60    impl<T: Config> Pallet<T> {
61        /// Calls the underlying RuntimeCall with Root origin.
62        #[pallet::call_index(0)]
63        #[pallet::weight({
64            let dispatch_info = call.get_dispatch_info();
65            (dispatch_info.call_weight.saturating_add(dispatch_info.extension_weight), DispatchClass::Mandatory)
66        })]
67        pub fn sudo(origin: OriginFor<T>, call: Box<<T as Config>::RuntimeCall>) -> DispatchResult {
68            ensure_none(origin)?;
69
70            let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
71            Self::deposit_event(Event::Sudid {
72                sudo_result: res.map(|_| ()).map_err(|e| e.error),
73            });
74
75            Ok(())
76        }
77    }
78
79    #[pallet::inherent]
80    impl<T: Config> ProvideInherent for Pallet<T> {
81        type Call = Call<T>;
82        type Error = InherentError;
83        const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
84
85        fn create_inherent(data: &InherentData) -> Option<Self::Call> {
86            let inherent_data = data
87                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
88                .expect("Domain sudo inherent data not correctly encoded")
89                .expect("Domain sudo inherent data must be provided");
90
91            if let Some(encoded_call) = inherent_data.maybe_call {
92                let call = Box::new(T::IntoRuntimeCall::runtime_call(encoded_call));
93                Some(Call::sudo { call })
94            } else {
95                None
96            }
97        }
98
99        fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
100            let inherent_data = data
101                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
102                .expect("Domain sudo inherent data not correctly encoded")
103                .expect("Domain sudo inherent data must be provided");
104
105            Ok(if inherent_data.maybe_call.is_none() {
106                None
107            } else {
108                Some(InherentError::MissingRuntimeCall)
109            })
110        }
111
112        fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
113            let inherent_data = data
114                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
115                .expect("Domain sudo inherent data not correctly encoded")
116                .expect("Domain sudo inherent data must be provided");
117
118            if let Some(encoded_call) = inherent_data.maybe_call {
119                let runtime_call = Box::new(T::IntoRuntimeCall::runtime_call(encoded_call));
120                if let Call::sudo { call } = call
121                    && call != &runtime_call
122                {
123                    return Err(InherentError::IncorrectRuntimeCall);
124                }
125            } else {
126                return Err(InherentError::MissingRuntimeCall);
127            }
128
129            Ok(())
130        }
131
132        fn is_inherent(call: &Self::Call) -> bool {
133            matches!(call, Call::sudo { .. })
134        }
135    }
136}