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}
95
96/// Registrar report messages sent back to the parachain.
97///
98/// The variant's `#[codec(index)]` is the on-wire version tag.
99#[derive(
100 Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo, MaxEncodedLen,
101)]
102pub enum MessageToPara {
103 /// Version 1 of the registrar report messages to the parachain.
104 #[codec(index = 0)]
105 V1(MessageToParaV1),
106}
107
108/// Version 1 payloads for [`MessageToPara`].
109#[derive(
110 Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo, MaxEncodedLen,
111)]
112pub enum MessageToParaV1 {
113 /// Report how a registration requested with [`MessageToRelayV1::Register`] ended.
114 ///
115 /// `para_id` correlates the response with its request: a parachain only sends
116 /// [`MessageToRelayV1::Register`] for a para id that is reserved and otherwise idle, so at
117 /// most one request per para id is ever in flight. `message_id` echoes the request's id on
118 /// top, tying the two together across chains and in events.
119 #[codec(index = 0)]
120 RegisterResponse {
121 /// The para id the report is about.
122 para_id: ParaId,
123 /// The id of the [`MessageToRelayV1::Register`] this answers, echoed back.
124 message_id: u64,
125 /// Whether the registration was applied on the relay chain.
126 outcome: Outcome,
127 },
128 /// Answer a [`MessageToRelayV1::CancelRegistration`].
129 ///
130 /// `Ok(())` means the relay chain is no longer holding an authorization for this para id, so
131 /// the deposit can be released. The only refusal is
132 /// [`FailureReason::AlreadyRegistered`]: the code did land after all and the para is
133 /// registered, so the deposit stays where it is.
134 #[codec(index = 1)]
135 CancelResponse {
136 /// The para id the answer is about.
137 para_id: ParaId,
138 /// The id of the [`MessageToRelayV1::CancelRegistration`] this answers, echoed back.
139 message_id: u64,
140 /// Whether the authorization was dropped.
141 outcome: Outcome,
142 },
143}
144
145/// How a request ended.
146///
147/// `Ok(())` means the relay chain applied it, `Err(reason)` that it did not. Shared by every
148/// response in this protocol rather than one outcome type per request, the same way a pallet has
149/// one `Error` enum instead of one per extrinsic. Encodes as `0x00` for success and `0x01` plus
150/// the reason for failure.
151pub type Outcome = Result<(), FailureReason>;
152
153/// Why a request was rejected by the relay chain.
154#[derive(
155 Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, Debug, TypeInfo, MaxEncodedLen,
156)]
157pub enum FailureReason {
158 /// The relay chain already knows this para id.
159 ///
160 /// Also the answer to a [`MessageToRelayV1::CancelRegistration`] that came too late, because
161 /// the validation code landed first.
162 #[codec(index = 0)]
163 AlreadyRegistered,
164 /// The head data or the declared code length is not acceptable to the relay chain.
165 #[codec(index = 1)]
166 InvalidOnboardingData,
167 /// The relay chain is already holding as many pending registrations as it will accept.
168 #[codec(index = 3)]
169 TooManyPending,
170}
171
172/// The parachain registry, as `pallet-registrar-relay` needs to see it.
173///
174/// Implemented by whichever pallet owns parachain registration, typically `paras_registrar` on the
175/// relay chain. Lives here so neither side of the protocol has to depend on the other.
176pub trait ParachainRegistrar {
177 /// The account id used to identify a registration's manager.
178 type AccountId;
179
180 /// Whether head data and code of these sizes could be onboarded right now.
181 ///
182 /// Checked against the relay chain's live configuration so a doomed request can be rejected
183 /// before the user goes and uploads megabytes of code.
184 #[allow(clippy::result_unit_err)]
185 fn check_onboarding(head_len: u32, code_len: u32) -> Result<(), ()>;
186
187 /// Whether the relay chain already knows this para id.
188 fn is_registered(para_id: ParaId) -> bool;
189
190 /// Onboard `para_id` under `manager`.
191 ///
192 /// No deposit is taken: the manager's funds are held on the chain running
193 /// `pallet-registrar-para`.
194 fn register(
195 manager: Self::AccountId,
196 para_id: ParaId,
197 genesis_head: Vec<u8>,
198 validation_code: Vec<u8>,
199 ) -> sp_runtime::DispatchResult;
200}