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::{InherentError, InherentType, IntoRuntimeCall, INHERENT_IDENTIFIER};
35
36    #[pallet::config]
37    pub trait Config: frame_system::Config {
38        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
39        type RuntimeCall: Parameter
40            + UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
41            + GetDispatchInfo;
42        type IntoRuntimeCall: IntoRuntimeCall<<Self as Config>::RuntimeCall>;
43    }
44
45    #[pallet::event]
46    #[pallet::generate_deposit(pub (super) fn deposit_event)]
47    pub enum Event<T: Config> {
48        /// A sudo call just took place.
49        Sudid {
50            /// The result of the call made by the sudo user.
51            sudo_result: DispatchResult,
52        },
53    }
54
55    /// Pallet Domain Sudo
56    #[pallet::pallet]
57    #[pallet::without_storage_info]
58    pub struct Pallet<T>(_);
59
60    #[pallet::call]
61    impl<T: Config> Pallet<T> {
62        /// Calls the underlying RuntimeCall with Root origin.
63        #[pallet::call_index(0)]
64        #[pallet::weight({
65            let dispatch_info = call.get_dispatch_info();
66            (dispatch_info.call_weight + dispatch_info.extension_weight, DispatchClass::Mandatory)
67        })]
68        pub fn sudo(origin: OriginFor<T>, call: Box<<T as Config>::RuntimeCall>) -> DispatchResult {
69            ensure_none(origin)?;
70
71            let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
72            Self::deposit_event(Event::Sudid {
73                sudo_result: res.map(|_| ()).map_err(|e| e.error),
74            });
75
76            Ok(())
77        }
78    }
79
80    #[pallet::inherent]
81    impl<T: Config> ProvideInherent for Pallet<T> {
82        type Call = Call<T>;
83        type Error = InherentError;
84        const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
85
86        fn create_inherent(data: &InherentData) -> Option<Self::Call> {
87            let inherent_data = data
88                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
89                .expect("Domain sudo inherent data not correctly encoded")
90                .expect("Domain sudo inherent data must be provided");
91
92            if let Some(encoded_call) = inherent_data.maybe_call {
93                let call = Box::new(T::IntoRuntimeCall::runtime_call(encoded_call));
94                Some(Call::sudo { call })
95            } else {
96                None
97            }
98        }
99
100        fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
101            let inherent_data = data
102                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
103                .expect("Domain sudo inherent data not correctly encoded")
104                .expect("Domain sudo inherent data must be provided");
105
106            Ok(if inherent_data.maybe_call.is_none() {
107                None
108            } else {
109                Some(InherentError::MissingRuntimeCall)
110            })
111        }
112
113        fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
114            let inherent_data = data
115                .get_data::<InherentType>(&INHERENT_IDENTIFIER)
116                .expect("Domain sudo inherent data not correctly encoded")
117                .expect("Domain sudo inherent data must be provided");
118
119            if let Some(encoded_call) = inherent_data.maybe_call {
120                let runtime_call = Box::new(T::IntoRuntimeCall::runtime_call(encoded_call));
121                if let Call::sudo { call } = call {
122                    if call != &runtime_call {
123                        return Err(InherentError::IncorrectRuntimeCall);
124                    }
125                }
126            } else {
127                return Err(InherentError::MissingRuntimeCall);
128            }
129
130            Ok(())
131        }
132
133        fn is_inherent(call: &Self::Call) -> bool {
134            matches!(call, Call::sudo { .. })
135        }
136    }
137}