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

            
19
use alloc::vec::*;
20
use frame_support::{
21
	dispatch::DispatchResult,
22
	traits::{Currency, ReservableCurrency},
23
};
24
use polkadot_primitives::{HeadData, Id as ParaId, ValidationCode};
25

            
26
/// Parachain registration API.
27
pub 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)]
92
pub 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.
104
pub 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)]
164
pub 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

            
181
impl<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

            
204
pub 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)]
260
pub 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
}