polkadot_runtime_common/traits.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//! Traits used across pallets for Polkadot.
18
19use alloc::vec::*;
20use frame_support::{
21 dispatch::DispatchResult,
22 traits::{Currency, ReservableCurrency},
23};
24use polkadot_primitives::{HeadData, Id as ParaId, ValidationCode};
25
26/// Parachain registration API.
27pub trait Registrar {
28 /// The account ID type that encodes a parachain manager ID.
29 type AccountId;
30
31 /// Report the manager (permissioned owner) of a parachain, if there is one.
32 fn manager_of(id: ParaId) -> Option<Self::AccountId>;
33
34 /// All lease holding parachains. Ordered ascending by `ParaId`. On-demand
35 /// parachains are not included.
36 fn parachains() -> Vec<ParaId>;
37
38 /// Return if a `ParaId` is a lease holding Parachain.
39 fn is_parachain(id: ParaId) -> bool {
40 Self::parachains().binary_search(&id).is_ok()
41 }
42
43 /// Return if a `ParaId` is a Parathread (on-demand parachain).
44 fn is_parathread(id: ParaId) -> bool;
45
46 /// Return if a `ParaId` is registered in the system.
47 fn is_registered(id: ParaId) -> bool {
48 Self::is_parathread(id) || Self::is_parachain(id)
49 }
50
51 /// Apply a lock to the para registration so that it cannot be modified by
52 /// the manager directly. Instead the para must use its sovereign governance
53 /// or the governance of the relay chain.
54 fn apply_lock(id: ParaId);
55
56 /// Remove any lock on the para registration.
57 fn remove_lock(id: ParaId);
58
59 /// Register a Para ID under control of `who`. Registration may be
60 /// delayed by session rotation.
61 fn register(
62 who: Self::AccountId,
63 id: ParaId,
64 genesis_head: HeadData,
65 validation_code: ValidationCode,
66 ) -> DispatchResult;
67
68 /// Deregister a Para ID, free any data, and return any deposits.
69 fn deregister(id: ParaId) -> DispatchResult;
70
71 /// Elevate a para to parachain status.
72 fn make_parachain(id: ParaId) -> DispatchResult;
73
74 /// Downgrade lease holding parachain into parathread (on-demand parachain)
75 fn make_parathread(id: ParaId) -> DispatchResult;
76
77 #[cfg(any(feature = "runtime-benchmarks", test))]
78 fn worst_head_data() -> HeadData;
79
80 #[cfg(any(feature = "runtime-benchmarks", test))]
81 fn worst_validation_code() -> ValidationCode;
82
83 /// Execute any pending state transitions for paras.
84 /// For example onboarding to on-demand parachain, or upgrading on-demand to
85 /// lease holding parachain.
86 #[cfg(any(feature = "runtime-benchmarks", test))]
87 fn execute_pending_transitions();
88}
89
90/// Error type for something that went wrong with leasing.
91#[derive(Debug)]
92pub enum LeaseError {
93 /// Unable to reserve the funds in the leaser's account.
94 ReserveFailed,
95 /// There is already a lease on at least one period for the given para.
96 AlreadyLeased,
97 /// The period to be leased has already ended.
98 AlreadyEnded,
99 /// A lease period has not started yet, due to an offset in the starting block.
100 NoLeasePeriod,
101}
102
103/// Lease manager. Used by the auction module to handle parachain slot leases.
104pub trait Leaser<BlockNumber> {
105 /// An account identifier for a leaser.
106 type AccountId;
107
108 /// The measurement type for counting lease periods (generally just a `BlockNumber`).
109 type LeasePeriod;
110
111 /// The currency type in which the lease is taken.
112 type Currency: ReservableCurrency<Self::AccountId>;
113
114 /// Lease a new parachain slot for `para`.
115 ///
116 /// `leaser` shall have a total of `amount` balance reserved by the implementer of this trait.
117 ///
118 /// Note: The implementer of the trait (the leasing system) is expected to do all
119 /// reserve/unreserve calls. The caller of this trait *SHOULD NOT* pre-reserve the deposit
120 /// (though should ensure that it is reservable).
121 ///
122 /// The lease will last from `period_begin` for `period_count` lease periods. It is undefined if
123 /// the `para` already has a slot leased during those periods.
124 ///
125 /// Returns `Err` in the case of an error, and in which case nothing is changed.
126 fn lease_out(
127 para: ParaId,
128 leaser: &Self::AccountId,
129 amount: <Self::Currency as Currency<Self::AccountId>>::Balance,
130 period_begin: Self::LeasePeriod,
131 period_count: Self::LeasePeriod,
132 ) -> Result<(), LeaseError>;
133
134 /// Return the amount of balance currently held in reserve on `leaser`'s account for leasing
135 /// `para`. This won't go down outside a lease period.
136 fn deposit_held(
137 para: ParaId,
138 leaser: &Self::AccountId,
139 ) -> <Self::Currency as Currency<Self::AccountId>>::Balance;
140
141 /// The length of a lease period, and any offset which may be introduced.
142 /// This is only used in benchmarking to automate certain calls.
143 #[cfg(any(feature = "runtime-benchmarks", test))]
144 fn lease_period_length() -> (BlockNumber, BlockNumber);
145
146 /// Returns the lease period at `block`, and if this is the first block of a new lease period.
147 ///
148 /// Will return `None` if the first lease period has not started yet, for example when an offset
149 /// is placed.
150 fn lease_period_index(block: BlockNumber) -> Option<(Self::LeasePeriod, bool)>;
151
152 /// Returns true if the parachain already has a lease in any of lease periods in the inclusive
153 /// range `[first_period, last_period]`, intersected with the unbounded range
154 /// [`current_lease_period`..] .
155 fn already_leased(
156 para_id: ParaId,
157 first_period: Self::LeasePeriod,
158 last_period: Self::LeasePeriod,
159 ) -> bool;
160}
161
162/// An enum which tracks the status of the auction system, and which phase it is in.
163#[derive(PartialEq, Debug)]
164pub enum AuctionStatus<BlockNumber> {
165 /// An auction has not started yet.
166 NotStarted,
167 /// We are in the starting period of the auction, collecting initial bids.
168 StartingPeriod,
169 /// We are in the ending period of the auction, where we are taking snapshots of the winning
170 /// bids. This state supports "sampling", where we may only take a snapshot every N blocks.
171 /// In this case, the first number is the current sample number, and the second number
172 /// is the sub-sample. i.e. for sampling every 20 blocks, the 25th block in the ending period
173 /// will be `EndingPeriod(1, 5)`.
174 EndingPeriod(BlockNumber, BlockNumber),
175 /// We have completed the bidding process and are waiting for the VRF to return some acceptable
176 /// randomness to select the winner. The number represents how many blocks we have been
177 /// waiting.
178 VrfDelay(BlockNumber),
179}
180
181impl<BlockNumber> AuctionStatus<BlockNumber> {
182 /// Returns true if the auction is in any state other than `NotStarted`.
183 pub fn is_in_progress(&self) -> bool {
184 !matches!(self, Self::NotStarted)
185 }
186 /// Return true if the auction is in the starting period.
187 pub fn is_starting(&self) -> bool {
188 matches!(self, Self::StartingPeriod)
189 }
190 /// Returns `Some(sample, sub_sample)` if the auction is in the `EndingPeriod`,
191 /// otherwise returns `None`.
192 pub fn is_ending(self) -> Option<(BlockNumber, BlockNumber)> {
193 match self {
194 Self::EndingPeriod(sample, sub_sample) => Some((sample, sub_sample)),
195 _ => None,
196 }
197 }
198 /// Returns true if the auction is in the `VrfDelay` period.
199 pub fn is_vrf(&self) -> bool {
200 matches!(self, Self::VrfDelay(_))
201 }
202}
203
204pub trait Auctioneer<BlockNumber> {
205 /// An account identifier for a leaser.
206 type AccountId;
207
208 /// The measurement type for counting lease periods (generally the same as `BlockNumber`).
209 type LeasePeriod;
210
211 /// The currency type in which the lease is taken.
212 type Currency: ReservableCurrency<Self::AccountId>;
213
214 /// Create a new auction.
215 ///
216 /// This can only happen when there isn't already an auction in progress. Accepts the `duration`
217 /// of this auction and the `lease_period_index` of the initial lease period of the four that
218 /// are to be auctioned.
219 fn new_auction(duration: BlockNumber, lease_period_index: Self::LeasePeriod) -> DispatchResult;
220
221 /// Given the current block number, return the current auction status.
222 fn auction_status(now: BlockNumber) -> AuctionStatus<BlockNumber>;
223
224 /// Place a bid in the current auction.
225 ///
226 /// - `bidder`: The account that will be funding this bid.
227 /// - `para`: The para to bid for.
228 /// - `first_slot`: The first lease period index of the range to be bid on.
229 /// - `last_slot`: The last lease period index of the range to be bid on (inclusive).
230 /// - `amount`: The total amount to be the bid for deposit over the range.
231 ///
232 /// The account `Bidder` must have at least `amount` available as a free balance in `Currency`.
233 /// The implementation *MUST* remove or reserve `amount` funds from `bidder` and those funds
234 /// should be returned or freed once the bid is rejected or lease has ended.
235 fn place_bid(
236 bidder: Self::AccountId,
237 para: ParaId,
238 first_slot: Self::LeasePeriod,
239 last_slot: Self::LeasePeriod,
240 amount: <Self::Currency as Currency<Self::AccountId>>::Balance,
241 ) -> DispatchResult;
242
243 /// The length of a lease period, and any offset which may be introduced.
244 /// This is only used in benchmarking to automate certain calls.
245 #[cfg(any(feature = "runtime-benchmarks", test))]
246 fn lease_period_length() -> (BlockNumber, BlockNumber);
247
248 /// Returns the lease period at `block`, and if this is the first block of a new lease period.
249 ///
250 /// Will return `None` if the first lease period has not started yet, for example when an offset
251 /// is placed.
252 fn lease_period_index(block: BlockNumber) -> Option<(Self::LeasePeriod, bool)>;
253
254 /// Check if the para and user combination has won an auction in the past.
255 fn has_won_an_auction(para: ParaId, bidder: &Self::AccountId) -> bool;
256}
257
258/// Runtime hook for when we swap a lease holding parachain and an on-demand parachain.
259#[impl_trait_for_tuples::impl_for_tuples(30)]
260pub trait OnSwap {
261 /// Updates any needed state/references to enact a logical swap of two parachains. Identity,
262 /// code and `head_data` remain equivalent for all parachains/threads, however other properties
263 /// such as leases, deposits held and thread/chain nature are swapped.
264 fn on_swap(one: ParaId, other: ParaId);
265}