// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot 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. // Polkadot 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 Polkadot. If not, see . //! A simple wrapper allowing `Sudo` to call into `paras` routines. use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; pub use pallet::*; use parity_scale_codec::Encode; use primitives::Id as ParaId; use runtime_parachains::{ configuration, dmp, hrmp, paras::{self, ParaGenesisArgs}, ParaLifecycle, }; use sp_std::boxed::Box; #[frame_support::pallet] pub mod pallet { use super::*; #[pallet::pallet] pub struct Pallet(_); #[pallet::config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: configuration::Config + paras::Config + dmp::Config + hrmp::Config {} #[pallet::error] pub enum Error { /// The specified parachain is not registered. ParaDoesntExist, /// The specified parachain is already registered. ParaAlreadyExists, /// A DMP message couldn't be sent because it exceeds the maximum size allowed for a /// downward message. ExceedsMaxMessageSize, /// Could not schedule para cleanup. CouldntCleanup, /// Not a parathread (on-demand parachain). NotParathread, /// Not a lease holding parachain. NotParachain, /// Cannot upgrade on-demand parachain to lease holding parachain. CannotUpgrade, /// Cannot downgrade lease holding parachain to on-demand. CannotDowngrade, } #[pallet::hooks] impl Hooks> for Pallet {} #[pallet::call] impl Pallet { /// Schedule a para to be initialized at the start of the next session. #[pallet::call_index(0)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_para_initialize( origin: OriginFor, id: ParaId, genesis: ParaGenesisArgs, ) -> DispatchResult { ensure_root(origin)?; runtime_parachains::schedule_para_initialize::(id, genesis) .map_err(|_| Error::::ParaAlreadyExists)?; Ok(()) } /// Schedule a para to be cleaned up at the start of the next session. #[pallet::call_index(1)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_para_cleanup(origin: OriginFor, id: ParaId) -> DispatchResult { ensure_root(origin)?; runtime_parachains::schedule_para_cleanup::(id) .map_err(|_| Error::::CouldntCleanup)?; Ok(()) } /// Upgrade a parathread (on-demand parachain) to a lease holding parachain #[pallet::call_index(2)] #[pallet::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 parachain)... ensure!( paras::Pallet::::lifecycle(id) == Some(ParaLifecycle::Parathread), Error::::NotParathread, ); runtime_parachains::schedule_parathread_upgrade::(id) .map_err(|_| Error::::CannotUpgrade)?; Ok(()) } /// Downgrade a lease holding parachain to an on-demand parachain #[pallet::call_index(3)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_schedule_parachain_downgrade( origin: OriginFor, id: ParaId, ) -> DispatchResult { ensure_root(origin)?; // Para backend should think this is a parachain... ensure!( paras::Pallet::::lifecycle(id) == Some(ParaLifecycle::Parachain), Error::::NotParachain, ); runtime_parachains::schedule_parachain_downgrade::(id) .map_err(|_| Error::::CannotDowngrade)?; Ok(()) } /// Send a downward XCM to the given para. /// /// The given parachain should exist and the payload should not exceed the preconfigured /// size `config.max_downward_message_size`. #[pallet::call_index(4)] #[pallet::weight((1_000, DispatchClass::Operational))] pub fn sudo_queue_downward_xcm( origin: OriginFor, id: ParaId, xcm: Box, ) -> DispatchResult { ensure_root(origin)?; ensure!(>::is_valid_para(id), Error::::ParaDoesntExist); let config = >::config(); >::queue_downward_message(&config, id, xcm.encode()).map_err(|e| match e { dmp::QueueDownwardMessageError::ExceedsMaxMessageSize => Error::::ExceedsMaxMessageSize.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`. #[pallet::call_index(5)] #[pallet::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)?; >::init_open_channel( sender, recipient, max_capacity, max_message_size, )?; >::accept_open_channel(recipient, sender)?; Ok(()) } } }