204 lines
5.0 KiB
Rust
204 lines
5.0 KiB
Rust
#![cfg_attr(not(feature = "std"), no_std)]
|
|
|
|
use sp_runtime::{traits::StaticLookup, DispatchResult};
|
|
use sp_std::prelude::*;
|
|
|
|
use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable};
|
|
|
|
mod extension;
|
|
#[cfg(test)]
|
|
mod mock;
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
#[cfg(feature = "runtime-benchmarks")]
|
|
mod benchmarking;
|
|
pub mod weights;
|
|
pub use weights::WeightInfo;
|
|
|
|
pub use extension::CheckOnlySudoAccount;
|
|
pub use pallet::*;
|
|
|
|
type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
|
|
|
|
#[frame_support::pallet]
|
|
pub mod pallet {
|
|
use super::{DispatchResult, *};
|
|
use frame_support::pallet_prelude::*;
|
|
use frame_system::{pallet_prelude::*, RawOrigin};
|
|
|
|
pub mod config_preludes {
|
|
use super::*;
|
|
use frame_support::derive_impl;
|
|
|
|
pub struct TestDefaultConfig;
|
|
|
|
#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
|
|
impl frame_system::DefaultConfig for TestDefaultConfig {}
|
|
|
|
#[frame_support::register_default_impl(TestDefaultConfig)]
|
|
impl DefaultConfig for TestDefaultConfig {
|
|
type WeightInfo = ();
|
|
#[inject_runtime_type]
|
|
type RuntimeEvent = ();
|
|
#[inject_runtime_type]
|
|
type RuntimeCall = ();
|
|
}
|
|
}
|
|
#[pallet::config(with_default)]
|
|
pub trait Config: frame_system::Config {
|
|
#[pallet::no_default_bounds]
|
|
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
|
|
|
#[pallet::no_default_bounds]
|
|
type RuntimeCall: Parameter
|
|
+ UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
|
|
+ GetDispatchInfo;
|
|
|
|
type WeightInfo: WeightInfo;
|
|
}
|
|
|
|
#[pallet::pallet]
|
|
pub struct Pallet<T>(_);
|
|
|
|
#[pallet::call]
|
|
impl<T: Config> Pallet<T> {
|
|
#[pallet::call_index(0)]
|
|
#[pallet::weight({
|
|
let dispatch_info = call.get_dispatch_info();
|
|
(
|
|
T::WeightInfo::sudo().saturating_add(dispatch_info.weight),
|
|
dispatch_info.class
|
|
)
|
|
})]
|
|
pub fn sudo(
|
|
origin: OriginFor<T>,
|
|
call: Box<<T as Config>::RuntimeCall>,
|
|
) -> DispatchResultWithPostInfo {
|
|
Self::ensure_sudo(origin)?;
|
|
|
|
let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
|
|
Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) });
|
|
|
|
Ok(Pays::No.into())
|
|
}
|
|
|
|
#[pallet::call_index(1)]
|
|
#[pallet::weight((*weight, call.get_dispatch_info().class))]
|
|
pub fn sudo_unchecked_weight(
|
|
origin: OriginFor<T>,
|
|
call: Box<<T as Config>::RuntimeCall>,
|
|
weight: Weight,
|
|
) -> DispatchResultWithPostInfo {
|
|
Self::ensure_sudo(origin)?;
|
|
let _ = weight;
|
|
|
|
let res = call.dispatch_bypass_filter(RawOrigin::Root.into());
|
|
Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error) });
|
|
|
|
Ok(Pays::No.into())
|
|
}
|
|
|
|
#[pallet::call_index(2)]
|
|
#[pallet::weight(T::WeightInfo::set_key())]
|
|
pub fn set_key(
|
|
origin: OriginFor<T>,
|
|
new: AccountIdLookupOf<T>,
|
|
) -> DispatchResultWithPostInfo {
|
|
Self::ensure_sudo(origin)?;
|
|
|
|
let new = T::Lookup::lookup(new)?;
|
|
Self::deposit_event(Event::KeyChanged { old: Key::<T>::get(), new: new.clone() });
|
|
Key::<T>::put(new);
|
|
|
|
Ok(Pays::No.into())
|
|
}
|
|
|
|
#[pallet::call_index(3)]
|
|
#[pallet::weight({
|
|
let dispatch_info = call.get_dispatch_info();
|
|
(
|
|
T::WeightInfo::sudo_as().saturating_add(dispatch_info.weight),
|
|
dispatch_info.class,
|
|
)
|
|
})]
|
|
pub fn sudo_as(
|
|
origin: OriginFor<T>,
|
|
who: AccountIdLookupOf<T>,
|
|
call: Box<<T as Config>::RuntimeCall>,
|
|
) -> DispatchResultWithPostInfo {
|
|
Self::ensure_sudo(origin)?;
|
|
|
|
let who = T::Lookup::lookup(who)?;
|
|
let res = call.dispatch_bypass_filter(RawOrigin::Signed(who).into());
|
|
Self::deposit_event(Event::SudoAsDone {
|
|
sudo_result: res.map(|_| ()).map_err(|e| e.error),
|
|
});
|
|
|
|
Ok(Pays::No.into())
|
|
}
|
|
|
|
#[pallet::call_index(4)]
|
|
#[pallet::weight(T::WeightInfo::remove_key())]
|
|
pub fn remove_key(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
|
|
Self::ensure_sudo(origin)?;
|
|
|
|
Self::deposit_event(Event::KeyRemoved {});
|
|
Key::<T>::kill();
|
|
|
|
Ok(Pays::No.into())
|
|
}
|
|
}
|
|
|
|
#[pallet::event]
|
|
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
|
pub enum Event<T: Config> {
|
|
Sudid {
|
|
sudo_result: DispatchResult,
|
|
},
|
|
KeyChanged {
|
|
old: Option<T::AccountId>,
|
|
new: T::AccountId,
|
|
},
|
|
KeyRemoved,
|
|
SudoAsDone { sudo_result: DispatchResult },
|
|
}
|
|
|
|
#[pallet::error]
|
|
pub enum Error<T> {
|
|
RequireSudo,
|
|
}
|
|
|
|
#[pallet::storage]
|
|
pub(super) type Key<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;
|
|
|
|
#[pallet::genesis_config]
|
|
#[derive(frame_support::DefaultNoBound)]
|
|
pub struct GenesisConfig<T: Config> {
|
|
pub key: Option<T::AccountId>,
|
|
}
|
|
|
|
#[pallet::genesis_build]
|
|
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
|
fn build(&self) {
|
|
Key::<T>::set(self.key.clone());
|
|
}
|
|
}
|
|
|
|
impl<T: Config> Pallet<T> {
|
|
pub(crate) fn ensure_sudo(origin: OriginFor<T>) -> DispatchResult {
|
|
let sender = ensure_signed_or_root(origin)?;
|
|
|
|
if let Some(sender) = sender {
|
|
if Key::<T>::get().map_or(false, |k| k == sender) {
|
|
Ok(())
|
|
} else {
|
|
Err(Error::<T>::RequireSudo.into())
|
|
}
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|