// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // This file is part of Pezkuwi. // Pezkuwi is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Pezkuwi is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Pezkuwi. If not, see . //! A simple wrapper allowing `Sudo` to call into `paras` routines. use alloc::boxed::Box; use codec::Encode; use pezframe_support::pezpallet_prelude::*; use pezframe_system::pezpallet_prelude::*; use pezkuwi_primitives::Id as ParaId; use pezkuwi_runtime_teyrchains::{ configuration, dmp, hrmp, paras::{self, AssignCoretime, ParaGenesisArgs, ParaKind}, ParaLifecycle, }; pub use pezpallet::*; #[pezframe_support::pezpallet] pub mod pezpallet { use super::*; #[pezpallet::pezpallet] pub struct Pezpallet(_); #[pezpallet::config] #[pezpallet::disable_pezframe_system_supertrait_check] pub trait Config: configuration::Config + paras::Config + dmp::Config + hrmp::Config {} #[pezpallet::error] pub enum Error { /// The specified teyrchain is not registered. ParaDoesntExist, /// The specified teyrchain is already registered. ParaAlreadyExists, /// A DMP message couldn't be sent because it exceeds the maximum size allowed for a /// downward message. ExceedsMaxMessageSize, /// A DMP message couldn't be sent because the destination is unreachable. Unroutable, /// Could not schedule para cleanup. CouldntCleanup, /// Not a parathread (on-demand teyrchain). NotParathread, /// Not a lease holding teyrchain. NotTeyrchain, /// Cannot upgrade on-demand teyrchain to lease holding teyrchain. CannotUpgrade, /// Cannot downgrade lease holding teyrchain to on-demand. CannotDowngrade, /// There are more cores than supported by the runtime. TooManyCores, } #[pezpallet::hooks] impl Hooks> for Pezpallet {} #[pezpallet::call] impl Pezpallet { /// Schedule a para to be initialized at the start of the next session. /// /// This should only be used for TESTING and not on PRODUCTION chains. It automatically /// assigns Coretime to the chain and increases the number of cores. Thus, there is no /// running coretime chain required. #[pezpallet::call_index(0)] #[pezpallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_para_initialize( origin: OriginFor, id: ParaId, genesis: ParaGenesisArgs, ) -> DispatchResult { ensure_root(origin)?; let assign_coretime = genesis.para_kind == ParaKind::Teyrchain; pezkuwi_runtime_teyrchains::schedule_para_initialize::(id, genesis) .map_err(|_| Error::::ParaAlreadyExists)?; if assign_coretime { T::AssignCoretime::assign_coretime(id)?; } Ok(()) } /// Schedule a para to be cleaned up at the start of the next session. #[pezpallet::call_index(1)] #[pezpallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_para_cleanup(origin: OriginFor, id: ParaId) -> DispatchResult { ensure_root(origin)?; pezkuwi_runtime_teyrchains::schedule_para_cleanup::(id) .map_err(|_| Error::::CouldntCleanup)?; Ok(()) } /// Upgrade a parathread (on-demand teyrchain) to a lease holding teyrchain #[pezpallet::call_index(2)] #[pezpallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_parathread_upgrade( origin: OriginFor, id: ParaId, ) -> DispatchResult { ensure_root(origin)?; // Para backend should think this is a parathread (on-demand teyrchain)... ensure!( paras::Pezpallet::::lifecycle(id) == Some(ParaLifecycle::Parathread), Error::::NotParathread, ); pezkuwi_runtime_teyrchains::schedule_parathread_upgrade::(id) .map_err(|_| Error::::CannotUpgrade)?; Ok(()) } /// Downgrade a lease holding teyrchain to an on-demand teyrchain #[pezpallet::call_index(3)] #[pezpallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_teyrchain_downgrade( origin: OriginFor, id: ParaId, ) -> DispatchResult { ensure_root(origin)?; // Para backend should think this is a teyrchain... ensure!( paras::Pezpallet::::lifecycle(id) == Some(ParaLifecycle::Teyrchain), Error::::NotTeyrchain, ); pezkuwi_runtime_teyrchains::schedule_teyrchain_downgrade::(id) .map_err(|_| Error::::CannotDowngrade)?; Ok(()) } /// Send a downward XCM to the given para. /// /// The given teyrchain should exist and the payload should not exceed the preconfigured /// size `config.max_downward_message_size`. #[pezpallet::call_index(4)] #[pezpallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_queue_downward_xcm( origin: OriginFor, id: ParaId, xcm: Box, ) -> DispatchResult { ensure_root(origin)?; ensure!(paras::Pezpallet::::is_valid_para(id), Error::::ParaDoesntExist); let config = configuration::ActiveConfig::::get(); dmp::Pezpallet::::queue_downward_message(&config, id, xcm.encode()).map_err(|e| { match e { dmp::QueueDownwardMessageError::ExceedsMaxMessageSize => { Error::::ExceedsMaxMessageSize.into() }, dmp::QueueDownwardMessageError::Unroutable => Error::::Unroutable.into(), } }) } /// Forcefully establish a channel from the sender to the recipient. /// /// This is equivalent to sending an `Hrmp::hrmp_init_open_channel` extrinsic followed by /// `Hrmp::hrmp_accept_open_channel`. #[pezpallet::call_index(5)] #[pezpallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_establish_hrmp_channel( origin: OriginFor, sender: ParaId, recipient: ParaId, max_capacity: u32, max_message_size: u32, ) -> DispatchResult { ensure_root(origin)?; hrmp::Pezpallet::::init_open_channel( sender, recipient, max_capacity, max_message_size, )?; hrmp::Pezpallet::::accept_open_channel(recipient, sender)?; Ok(()) } } }