referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_common/
paras_sudo_wrapper.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! A simple wrapper allowing `Sudo` to call into `paras` routines.
18
19use alloc::boxed::Box;
20use codec::Encode;
21use frame_support::pallet_prelude::*;
22use frame_system::pallet_prelude::*;
23pub use pallet::*;
24use polkadot_primitives::Id as ParaId;
25use polkadot_runtime_parachains::{
26	configuration, dmp, hrmp,
27	paras::{self, AssignCoretime, ParaGenesisArgs, ParaKind},
28	ParaLifecycle,
29};
30
31#[frame_support::pallet]
32pub mod pallet {
33	use super::*;
34
35	#[pallet::pallet]
36	pub struct Pallet<T>(_);
37
38	#[pallet::config]
39	#[pallet::disable_frame_system_supertrait_check]
40	pub trait Config: configuration::Config + paras::Config + dmp::Config + hrmp::Config {}
41
42	#[pallet::error]
43	pub enum Error<T> {
44		/// The specified parachain is not registered.
45		ParaDoesntExist,
46		/// The specified parachain is already registered.
47		ParaAlreadyExists,
48		/// A DMP message couldn't be sent because it exceeds the maximum size allowed for a
49		/// downward message.
50		ExceedsMaxMessageSize,
51		/// A DMP message couldn't be sent because the destination's queue is full.
52		ExceedsMaxQueueSize,
53		/// A DMP message couldn't be sent because the destination is unreachable.
54		Unroutable,
55		/// Could not schedule para cleanup.
56		CouldntCleanup,
57		/// Not a parathread (on-demand parachain).
58		NotParathread,
59		/// Not a lease holding parachain.
60		NotParachain,
61		/// Cannot upgrade on-demand parachain to lease holding parachain.
62		CannotUpgrade,
63		/// Cannot downgrade lease holding parachain to on-demand.
64		CannotDowngrade,
65		/// There are more cores than supported by the runtime.
66		TooManyCores,
67	}
68
69	#[pallet::hooks]
70	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
71
72	#[pallet::call]
73	impl<T: Config> Pallet<T> {
74		/// Schedule a para to be initialized at the start of the next session.
75		///
76		/// This should only be used for TESTING and not on PRODUCTION chains. It automatically
77		/// assigns Coretime to the chain and increases the number of cores. Thus, there is no
78		/// running coretime chain required.
79		#[pallet::call_index(0)]
80		#[pallet::weight((1_000, DispatchClass::Operational))]
81		pub fn sudo_schedule_para_initialize(
82			origin: OriginFor<T>,
83			id: ParaId,
84			genesis: ParaGenesisArgs,
85		) -> DispatchResult {
86			ensure_root(origin)?;
87
88			let assign_coretime = genesis.para_kind == ParaKind::Parachain;
89
90			polkadot_runtime_parachains::schedule_para_initialize::<T>(id, genesis)
91				.map_err(|_| Error::<T>::ParaAlreadyExists)?;
92
93			if assign_coretime {
94				T::AssignCoretime::assign_coretime(id)?;
95			}
96
97			Ok(())
98		}
99
100		/// Schedule a para to be cleaned up at the start of the next session.
101		#[pallet::call_index(1)]
102		#[pallet::weight((1_000, DispatchClass::Operational))]
103		pub fn sudo_schedule_para_cleanup(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
104			ensure_root(origin)?;
105			polkadot_runtime_parachains::schedule_para_cleanup::<T>(id)
106				.map_err(|_| Error::<T>::CouldntCleanup)?;
107			Ok(())
108		}
109
110		/// Upgrade a parathread (on-demand parachain) to a lease holding parachain
111		#[pallet::call_index(2)]
112		#[pallet::weight((1_000, DispatchClass::Operational))]
113		pub fn sudo_schedule_parathread_upgrade(
114			origin: OriginFor<T>,
115			id: ParaId,
116		) -> DispatchResult {
117			ensure_root(origin)?;
118			// Para backend should think this is a parathread (on-demand parachain)...
119			ensure!(
120				paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parathread),
121				Error::<T>::NotParathread,
122			);
123			polkadot_runtime_parachains::schedule_parathread_upgrade::<T>(id)
124				.map_err(|_| Error::<T>::CannotUpgrade)?;
125			Ok(())
126		}
127
128		/// Downgrade a lease holding parachain to an on-demand parachain
129		#[pallet::call_index(3)]
130		#[pallet::weight((1_000, DispatchClass::Operational))]
131		pub fn sudo_schedule_parachain_downgrade(
132			origin: OriginFor<T>,
133			id: ParaId,
134		) -> DispatchResult {
135			ensure_root(origin)?;
136			// Para backend should think this is a parachain...
137			ensure!(
138				paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parachain),
139				Error::<T>::NotParachain,
140			);
141			polkadot_runtime_parachains::schedule_parachain_downgrade::<T>(id)
142				.map_err(|_| Error::<T>::CannotDowngrade)?;
143			Ok(())
144		}
145
146		/// Send a downward XCM to the given para.
147		///
148		/// The given parachain should exist and the payload should not exceed the preconfigured
149		/// size `config.max_downward_message_size`.
150		#[pallet::call_index(4)]
151		#[pallet::weight((1_000, DispatchClass::Operational))]
152		pub fn sudo_queue_downward_xcm(
153			origin: OriginFor<T>,
154			id: ParaId,
155			xcm: Box<xcm::opaque::VersionedXcm>,
156		) -> DispatchResult {
157			ensure_root(origin)?;
158			ensure!(paras::Pallet::<T>::is_valid_para(id), Error::<T>::ParaDoesntExist);
159			let config = configuration::ActiveConfig::<T>::get();
160			dmp::Pallet::<T>::queue_downward_message(&config, id, xcm.encode()).map_err(|e| match e
161			{
162				dmp::QueueDownwardMessageError::ExceedsMaxMessageSize => {
163					Error::<T>::ExceedsMaxMessageSize.into()
164				},
165				dmp::QueueDownwardMessageError::ExceedsMaxQueueSize => {
166					Error::<T>::ExceedsMaxQueueSize.into()
167				},
168				dmp::QueueDownwardMessageError::Unroutable => Error::<T>::Unroutable.into(),
169			})
170		}
171
172		/// Forcefully establish a channel from the sender to the recipient.
173		///
174		/// This is equivalent to sending an `Hrmp::hrmp_init_open_channel` extrinsic followed by
175		/// `Hrmp::hrmp_accept_open_channel`.
176		#[pallet::call_index(5)]
177		#[pallet::weight((1_000, DispatchClass::Operational))]
178		pub fn sudo_establish_hrmp_channel(
179			origin: OriginFor<T>,
180			sender: ParaId,
181			recipient: ParaId,
182			max_capacity: u32,
183			max_message_size: u32,
184		) -> DispatchResult {
185			ensure_root(origin)?;
186
187			hrmp::Pallet::<T>::init_open_channel(
188				sender,
189				recipient,
190				max_capacity,
191				max_message_size,
192			)?;
193			hrmp::Pallet::<T>::accept_open_channel(recipient, sender)?;
194			Ok(())
195		}
196	}
197}