registrar_primitives/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Parachain-registrar shared primitives
19//!
20//! Types shared by the parachain registrar pallet (`pallet-registrar-para`) and relay-chain
21//! registrar pallet (`pallet-registrar-relay`). This crate is deliberately free of any FRAME,
22//! XCM, or network-specific dependency, so a single version of the wire types serves Westend,
23//! Kusama and Polkadot, and so both pallets can depend on it without forming a dependency cycle.
24//!
25//! For the same reason the types here are plain: a para id is a `u32` (byte-compatible with the
26//! relay chain's `Id` newtype), head data and validation code are `Vec<u8>`, and a validation
27//! code hash is an [`H256`] (what `ValidationCodeHash` wraps). The same holds for
28//! [`ParachainRegistrar`], the interface the relay pallet drives the registry through: conversion
29//! to the relay chain's own types happens in the pallet implementing it.
30
31#![cfg_attr(not(feature = "std"), no_std)]
32
33extern crate alloc;
34
35use alloc::vec::Vec;
36use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
37use scale_info::TypeInfo;
38use sp_core::H256;
39
40/// A parachain id.
41///
42/// Byte-compatible with the relay chain's `Id`, which is a transparent `u32` newtype.
43pub type ParaId = u32;
44
45/// Registrar control-plane messages sent to the relay chain.
46///
47/// The variant's `#[codec(index)]` is the on-wire version tag.
48#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo)]
49pub enum MessageToRelay<AccountId> {
50 /// Version 1 of the registrar control-plane messages to the relay chain.
51 #[codec(index = 0)]
52 V1(MessageToRelayV1<AccountId>),
53}
54
55/// Version 1 payloads for [`MessageToRelay`].
56#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo)]
57pub enum MessageToRelayV1<AccountId> {
58 /// Ask the relay chain to accept a registration for `para_id`.
59 ///
60 /// The deposit for this registration is already held on the parachain; the relay chain takes
61 /// nothing. The validation code itself is not included: only its hash and length are, and the
62 /// blob is uploaded to the relay chain separately.
63 #[codec(index = 0)]
64 Register {
65 /// The para id being registered. Already reserved on the parachain.
66 para_id: ParaId,
67 /// The parachain's id for this message, echoed back in the response.
68 message_id: u64,
69 /// The account that manages this registration and holds the deposit on the parachain.
70 manager: AccountId,
71 /// The genesis head data of the new parachain.
72 genesis_head: Vec<u8>,
73 /// Blake2-256 hash of the validation code that will be uploaded.
74 code_hash: H256,
75 /// Length of the validation code that will be uploaded, in bytes.
76 ///
77 /// The deposit on the parachain was computed from this, so the relay chain must reject any
78 /// blob whose length differs.
79 code_len: u32,
80 },
81 /// Ask the relay chain to drop the authorization it is holding for `para_id`.
82 ///
83 /// Sent when the manager gives up on a registration whose validation code never arrived. The
84 /// relay chain never abandons an authorization by itself, so this is what ends a registration
85 /// that is going nowhere, and the manager pays for it. Answered with
86 /// [`MessageToParaV1::CancelResponse`].
87 #[codec(index = 1)]
88 CancelRegistration {
89 /// The para id whose authorization should be dropped.
90 para_id: ParaId,
91 /// The parachain's id for this message, echoed back in the response.
92 message_id: u64,
93 },
94 /// Ask the relay chain to drop `para_id` from the registry.
95 ///
96 /// The parachain has already checked that it holds neither a lease nor a region, but only the
97 /// relay chain knows whether the para is still live, locked, or has messages left in flight,
98 /// so the deposits stay held until it answers with [`MessageToParaV1::DeregisterResponse`].
99 ///
100 /// Idempotent, so this is also the retry when an answer never arrives: a para already gone or
101 /// on its way out is answered `Ok(())` rather than refused, which is what lets the parachain
102 /// tell a lost verdict from a refusal without a second kind of message.
103 #[codec(index = 2)]
104 Deregister {
105 /// The para id to drop.
106 para_id: ParaId,
107 /// The parachain's id for this message, echoed back in the response.
108 message_id: u64,
109 },
110 /// Ask the relay chain to authorize a validation code upgrade for `para_id`.
111 ///
112 /// As with a registration, the blob itself is not sent: the relay chain is told which bytes to
113 /// accept and they are uploaded to it separately. Answered with
114 /// [`MessageToParaV1::CodeUpgradeResponse`].
115 #[codec(index = 3)]
116 AuthorizeCodeUpgrade {
117 /// The para id being upgraded.
118 para_id: ParaId,
119 /// The parachain's id for this message, echoed back in the response.
120 message_id: u64,
121 /// Blake2-256 hash of the validation code that will be uploaded.
122 code_hash: H256,
123 /// Length of the validation code that will be uploaded, in bytes.
124 code_len: u32,
125 },
126 /// Ask the relay chain to set the current head data of `para_id`.
127 ///
128 /// The head data is small enough to travel with the request, so unlike a code upgrade this is
129 /// a single round trip. Answered with [`MessageToParaV1::SetHeadResponse`].
130 #[codec(index = 4)]
131 SetCurrentHead {
132 /// The para id whose head is being set.
133 para_id: ParaId,
134 /// The parachain's id for this message, echoed back in the response.
135 message_id: u64,
136 /// The new head data.
137 head: Vec<u8>,
138 },
139}
140
141/// Registrar report messages sent back to the parachain.
142///
143/// The variant's `#[codec(index)]` is the on-wire version tag.
144#[derive(
145 Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo, MaxEncodedLen,
146)]
147pub enum MessageToPara {
148 /// Version 1 of the registrar report messages to the parachain.
149 #[codec(index = 0)]
150 V1(MessageToParaV1),
151}
152
153/// Version 1 payloads for [`MessageToPara`].
154#[derive(
155 Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo, MaxEncodedLen,
156)]
157pub enum MessageToParaV1 {
158 /// Report how a registration requested with [`MessageToRelayV1::Register`] ended.
159 ///
160 /// `para_id` correlates the response with its request: a parachain only sends
161 /// [`MessageToRelayV1::Register`] for a para id that is reserved and otherwise idle, so at
162 /// most one request per para id is ever in flight. `message_id` echoes the request's id on
163 /// top, tying the two together across chains and in events.
164 #[codec(index = 0)]
165 RegisterResponse {
166 /// The para id the report is about.
167 para_id: ParaId,
168 /// The id of the [`MessageToRelayV1::Register`] this answers, echoed back.
169 message_id: u64,
170 /// Whether the registration was applied on the relay chain.
171 outcome: Outcome,
172 },
173 /// Answer a [`MessageToRelayV1::CancelRegistration`].
174 ///
175 /// `Ok(())` means the relay chain is no longer holding an authorization for this para id, so
176 /// the deposit can be released. The only refusal is
177 /// [`FailureReason::AlreadyRegistered`]: the code did land after all and the para is
178 /// registered, so the deposit stays where it is.
179 #[codec(index = 1)]
180 CancelResponse {
181 /// The para id the answer is about.
182 para_id: ParaId,
183 /// The id of the [`MessageToRelayV1::CancelRegistration`] this answers, echoed back.
184 message_id: u64,
185 /// Whether the authorization was dropped.
186 outcome: Outcome,
187 },
188 /// Answer a [`MessageToRelayV1::Deregister`].
189 ///
190 /// `Ok(())` means the para is gone from the relay chain's registry, so every deposit the
191 /// parachain is holding for it can be released.
192 #[codec(index = 2)]
193 DeregisterResponse {
194 /// The para id the answer is about.
195 para_id: ParaId,
196 /// The id of the [`MessageToRelayV1::Deregister`] this answers, echoed back.
197 message_id: u64,
198 /// Whether the para was dropped.
199 outcome: Outcome,
200 },
201 /// Answer a [`MessageToRelayV1::AuthorizeCodeUpgrade`].
202 ///
203 /// `Ok(expire_at)` means the relay chain is holding the authorization and will accept the blob
204 /// until that relay-chain block. The upgrade is not scheduled yet: that is reported separately
205 /// with [`MessageToParaV1::CodeUpgradeScheduled`] once the code lands.
206 #[codec(index = 3)]
207 CodeUpgradeResponse {
208 /// The para id the answer is about.
209 para_id: ParaId,
210 /// The id of the [`MessageToRelayV1::AuthorizeCodeUpgrade`] this answers, echoed back.
211 message_id: u64,
212 /// The relay-chain block the authorization lapses at, or why it was refused.
213 outcome: Result<u32, FailureReason>,
214 },
215 /// Report that an authorized code upgrade has been scheduled on the relay chain.
216 ///
217 /// Sent when the blob is uploaded, which may be many blocks after the authorization and is not
218 /// something the parachain asked for, so this carries no outcome: a failure to upload simply
219 /// leaves the authorization to lapse.
220 #[codec(index = 4)]
221 CodeUpgradeScheduled {
222 /// The para id the report is about.
223 para_id: ParaId,
224 /// The id of the [`MessageToRelayV1::AuthorizeCodeUpgrade`] this concludes, echoed back.
225 message_id: u64,
226 },
227 /// Answer a [`MessageToRelayV1::SetCurrentHead`].
228 ///
229 /// The parachain checks the head against its own mirror of the relay chain's limits first, so
230 /// a refusal here means the two have drifted apart.
231 #[codec(index = 5)]
232 SetHeadResponse {
233 /// The para id the answer is about.
234 para_id: ParaId,
235 /// The id of the [`MessageToRelayV1::SetCurrentHead`] this answers, echoed back.
236 message_id: u64,
237 /// Whether the head was set.
238 outcome: Outcome,
239 },
240 /// Note that `para_id` has produced a head on the relay chain.
241 ///
242 /// Correlates with no request, so it carries no `message_id` and is not answered.
243 #[codec(index = 6)]
244 HeadNoted {
245 /// The para id that produced a head.
246 para_id: ParaId,
247 },
248}
249
250/// How a request ended.
251///
252/// `Ok(())` means the relay chain applied it, `Err(reason)` that it did not. Shared by every
253/// response in this protocol rather than one outcome type per request, the same way a pallet has
254/// one `Error` enum instead of one per extrinsic. Encodes as `0x00` for success and `0x01` plus
255/// the reason for failure.
256pub type Outcome = Result<(), FailureReason>;
257
258/// Why a request was rejected by the relay chain.
259#[derive(
260 Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo, MaxEncodedLen,
261)]
262pub enum FailureReason {
263 /// The relay chain already knows this para id.
264 ///
265 /// Also the answer to a [`MessageToRelayV1::CancelRegistration`] that came too late, because
266 /// the validation code landed first.
267 #[codec(index = 0)]
268 AlreadyRegistered,
269 /// The head data or the declared code length is not acceptable to the relay chain.
270 #[codec(index = 1)]
271 InvalidOnboardingData,
272 // Index 2 is reserved for `NotRegistered`, which lands with the deregister flow.
273 /// The relay chain is already holding as many pending registrations as it will accept.
274 #[codec(index = 3)]
275 TooManyPending,
276 /// The relay chain will not drop this para: it is not an on-demand parathread, or its
277 /// offboarding could not be scheduled (e.g. a PVF pre-check is still in progress).
278 #[codec(index = 4)]
279 NotDeregisterable,
280}
281
282/// The parachain registry, as `pallet-registrar-relay` needs to see it.
283///
284/// Implemented by whichever pallet owns parachain registration, typically `paras_registrar` on the
285/// relay chain. Lives here so neither side of the protocol has to depend on the other.
286pub trait ParachainRegistrar {
287 /// The account id used to identify a registration's manager.
288 type AccountId;
289
290 /// Whether head data and code of these sizes could be onboarded right now.
291 ///
292 /// Checked against the relay chain's live configuration so a doomed request can be rejected
293 /// before the user goes and uploads megabytes of code.
294 #[allow(clippy::result_unit_err)]
295 fn check_onboarding(head_len: u32, code_len: u32) -> Result<(), ()>;
296
297 /// Whether the relay chain already knows this para id.
298 fn is_registered(para_id: ParaId) -> bool;
299
300 /// Onboard `para_id` under `manager`.
301 ///
302 /// No deposit is taken: the manager's funds are held on the chain running
303 /// `pallet-registrar-para`.
304 fn register(
305 manager: Self::AccountId,
306 para_id: ParaId,
307 genesis_head: Vec<u8>,
308 validation_code: Vec<u8>,
309 ) -> sp_runtime::DispatchResult;
310
311 /// Drop `para_id` from the registry.
312 ///
313 /// Idempotent: a para already gone, or still being cleaned up, answers `Ok(())` rather than
314 /// refusing, so a second [`MessageToRelayV1::Deregister`] settles instead of telling the
315 /// parachain the para is still there. Nothing here retries on its own: the parachain waits,
316 /// and if no answer turns up the manager sends the request again. That second request is how
317 /// the parachain learns the first answer never came, and it reports it as an unexpected event.
318 fn deregister(para_id: ParaId) -> sp_runtime::DispatchResult;
319
320 /// Leave `para_id` where [`Self::deregister`] does the most work and still succeeds.
321 #[cfg(feature = "runtime-benchmarks")]
322 fn setup_worst_case_deregister(para_id: ParaId) -> sp_runtime::DispatchResult;
323
324 /// Whether head data of this size is acceptable right now.
325 #[allow(clippy::result_unit_err)]
326 fn check_head_data(head_len: u32) -> Result<(), ()>;
327
328 /// Set the current head of `para_id`.
329 fn set_current_head(para_id: ParaId, head: Vec<u8>);
330
331 /// Whether `para_id` could take a code upgrade of this size right now.
332 #[allow(clippy::result_unit_err)]
333 fn check_code_upgrade(para_id: ParaId, code_len: u32) -> Result<(), ()>;
334
335 /// Schedule a validation code upgrade for `para_id`.
336 fn schedule_code_upgrade(
337 para_id: ParaId,
338 validation_code: Vec<u8>,
339 ) -> sp_runtime::DispatchResult;
340}
341
342/// State of migrated para at the source chain.
343#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo)]
344pub enum MigratedParaState {
345 /// The para id is held by its manager, but nothing is registered on the relay chain.
346 Reserved,
347 /// The relay chain has onboarded this para.
348 Registered {
349 /// Length of the para's current head data, so the destination prices the registration
350 /// the way it prices a fresh one.
351 head_len: u32,
352 },
353}
354
355/// One para, as it arrives from source chain that used to own the registry.
356///
357/// Carries no deposit. [`ReceiveMigratedParas::receive_para`] takes the reservation deposit,
358/// and for a registered para the registration deposit, from `manager` at the destination's own
359/// prices.
360///
361/// Note: We recreate even if there is not enough fund to pay for the deposit so no RC para
362/// is dropped.
363#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo)]
364pub struct MigratedPara<AccountId> {
365 /// The para id.
366 pub para_id: ParaId,
367 /// The account that reserved the para id and controls it.
368 pub manager: AccountId,
369 /// Where this para id sits in the registration flow.
370 pub state: MigratedParaState,
371 /// Whether the manager is locked out of controlling this para. `None` until the lock is set
372 /// for the first time, and read as unlocked.
373 pub locked: Option<bool>,
374}
375
376/// Takes migrated para ids into the pallet that owns registration on the destination.
377pub trait ReceiveMigratedParas<AccountId> {
378 /// Take one para, charging its deposits at this chain's prices.
379 ///
380 /// Note: We recreate even if there is not enough fund to pay for the deposit so no RC para
381 /// gets dropped.
382 fn receive_para(para: MigratedPara<AccountId>) -> sp_runtime::DispatchResult;
383
384 /// Adopt the next free para id from the source chain.
385 fn receive_next_free_para_id(para_id: ParaId);
386}
387
388impl<AccountId> ReceiveMigratedParas<AccountId> for () {
389 fn receive_para(_: MigratedPara<AccountId>) -> sp_runtime::DispatchResult {
390 Err(sp_runtime::DispatchError::Unavailable)
391 }
392
393 fn receive_next_free_para_id(_: ParaId) {}
394}