pallet_domain_sudo/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
19#![expect(clippy::clone_on_copy, reason = "Comes from Substrate")]
21
22#[cfg(not(feature = "std"))]
23extern crate alloc;
24
25pub use pallet::*;
26
27#[frame_support::pallet]
28mod pallet {
29 #[cfg(not(feature = "std"))]
30 use alloc::boxed::Box;
31 use frame_support::dispatch::{GetDispatchInfo, RawOrigin};
32 use frame_support::pallet_prelude::*;
33 use frame_support::traits::UnfilteredDispatchable;
34 use frame_system::ensure_none;
35 use frame_system::pallet_prelude::OriginFor;
36 use sp_domain_sudo::{INHERENT_IDENTIFIER, InherentError, InherentType, IntoRuntimeCall};
37
38 #[pallet::config]
39 pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
40 type RuntimeCall: Parameter
41 + UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
42 + GetDispatchInfo;
43 type IntoRuntimeCall: IntoRuntimeCall<<Self as Config>::RuntimeCall>;
44 }
45
46 #[pallet::event]
47 #[pallet::generate_deposit(pub (super) fn deposit_event)]
48 pub enum Event<T: Config> {
49 Sudid {
51 sudo_result: DispatchResult,
53 },
54 }
55
56 #[pallet::pallet]
58 #[pallet::without_storage_info]
59 pub struct Pallet<T>(_);
60
61 #[pallet::call]
62 impl<T: Config> Pallet<T> {
63 #[pallet::call_index(0)]
65 #[pallet::weight({
66 let dispatch_info = call.get_dispatch_info();
67 (dispatch_info.call_weight.saturating_add(dispatch_info.extension_weight), DispatchClass::Mandatory)
68 })]
69 pub fn sudo(origin: OriginFor<T>, call: Box<<T as Config>::RuntimeCall>) -> DispatchResult {
70 ensure_none(origin)?;
71
72 let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
73 Self::deposit_event(Event::Sudid {
74 sudo_result: res.map(|_| ()).map_err(|e| e.error),
75 });
76
77 Ok(())
78 }
79 }
80
81 #[pallet::inherent]
82 impl<T: Config> ProvideInherent for Pallet<T> {
83 type Call = Call<T>;
84 type Error = InherentError;
85 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
86
87 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
88 let inherent_data = data
89 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
90 .expect("Domain sudo inherent data not correctly encoded")
91 .expect("Domain sudo inherent data must be provided");
92
93 if let Some(encoded_call) = inherent_data.maybe_call {
94 let call = Box::new(T::IntoRuntimeCall::runtime_call(encoded_call));
95 Some(Call::sudo { call })
96 } else {
97 None
98 }
99 }
100
101 fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
102 let inherent_data = data
103 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
104 .expect("Domain sudo inherent data not correctly encoded")
105 .expect("Domain sudo inherent data must be provided");
106
107 Ok(if inherent_data.maybe_call.is_none() {
108 None
109 } else {
110 Some(InherentError::MissingRuntimeCall)
111 })
112 }
113
114 fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
115 let inherent_data = data
116 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
117 .expect("Domain sudo inherent data not correctly encoded")
118 .expect("Domain sudo inherent data must be provided");
119
120 if let Some(encoded_call) = inherent_data.maybe_call {
121 let runtime_call = Box::new(T::IntoRuntimeCall::runtime_call(encoded_call));
122 if let Call::sudo { call } = call
123 && call != &runtime_call
124 {
125 return Err(InherentError::IncorrectRuntimeCall);
126 }
127 } else {
128 return Err(InherentError::MissingRuntimeCall);
129 }
130
131 Ok(())
132 }
133
134 fn is_inherent(call: &Self::Call) -> bool {
135 matches!(call, Call::sudo { .. })
136 }
137 }
138}