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