Newer
Older
// Copyright 2019 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/>.
//! Auctioning system to determine the set of Parachains in operation. This includes logic for the
//! auctioning mechanism, for locking balance as part of the "payment", and to provide the requisite
//! information for commissioning and decommissioning them.
use rstd::{prelude::*, mem::swap, convert::TryInto};
use sp_runtime::traits::{
CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash, AccountIdConversion,
};
use frame_support::weights::SimpleDispatchInfo;
decl_module, decl_storage, decl_event, ensure,
traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get, Randomness},
use primitives::parachain::{
SwapAux, PARACHAIN_INFO, Id as ParaId
};
use system::{ensure_signed, ensure_root};
use crate::registrar::{Registrar, swap_ordered_existence};
use crate::slot_range::{SlotRange, SLOT_RANGE_COUNT};
type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
/// The module's configuration trait.
pub trait Trait: system::Trait {
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
/// The currency type used for bidding.
type Currency: ReservableCurrency<Self::AccountId>;
/// The parachain registrar type.
type Parachains: Registrar<Self::AccountId>;
/// The number of blocks over which an auction may be retroactively ended.
type EndingPeriod: Get<Self::BlockNumber>;
/// The number of blocks over which a single period lasts.
type LeasePeriod: Get<Self::BlockNumber>;
/// Something that provides randomness in the runtime.
type Randomness: Randomness<Self::Hash>;
}
/// A sub-bidder identifier. Used to distinguish between different logical bidders coming from the
/// same account ID.
pub type SubId = u32;
/// An auction index. We count auctions in this type.
pub type AuctionIndex = u32;
/// A bidder identifier, which is just the combination of an account ID and a sub-bidder ID.
/// This is called `NewBidder` in order to distinguish between bidders that would deploy a *new*
/// parachain and pre-existing parachains bidding to renew themselves.
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct NewBidder<AccountId> {
/// The bidder's account ID; this is the account that funds the bid.
/// An additional ID to allow the same account ID (and funding source) to have multiple
/// logical bidders.
}
/// The desired target of a bidder in an auction.
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
/// An account ID, funds coming from that account.
New(NewBidder<AccountId>),
/// An existing parachain, funds coming from the amount locked as part of a previous bid topped
/// up with funds administered by the parachain.
Existing(ParaId),
}
impl<AccountId: Clone + Default + Codec> Bidder<AccountId> {
/// Get the account that will fund this bid.
fn funding_account(&self) -> AccountId {
match self {
Bidder::New(new_bidder) => new_bidder.who.clone(),
Bidder::Existing(para_id) => para_id.into_account(),
}
}
}
/// Information regarding a parachain that will be deployed.
///
/// We store either the bidder that will be able to set the final deployment information or the
/// information itself.
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum IncomingParachain<AccountId, Hash> {
/// Deploy information not yet set; just the bidder identity.
Unset(NewBidder<AccountId>),
/// Deploy information set only by code hash; so we store the code hash and head data.
Fixed { code_hash: Hash, initial_head_data: Vec<u8> },
/// Deploy information fully set; so we store the code and head data.
Deploy { code: Vec<u8>, initial_head_data: Vec<u8> },
}
type LeasePeriodOf<T> = <T as system::Trait>::BlockNumber;
// Winning data type. This encodes the top bidders of each range together with their bid.
type WinningData<T> =
[Option<(Bidder<<T as system::Trait>::AccountId>, BalanceOf<T>)>; SLOT_RANGE_COUNT];
// Winners data type. This encodes each of the final winners of a parachain auction, the parachain
// index assigned to them, their winning bid and the range that they won.
type WinnersData<T> =
Vec<(Option<NewBidder<<T as system::Trait>::AccountId>>, ParaId, BalanceOf<T>, SlotRange)>;
// This module's storage items.
decl_storage! {
trait Store for Module<T: Trait> as Slots {
/// The number of auctions that have been started so far.
pub AuctionCounter get(auction_counter): AuctionIndex;
/// Ordered list of all `ParaId` values that are managed by this module. This includes
/// chains that are not yet deployed (but have won an auction in the future).
pub ManagedIds get(managed_ids): Vec<ParaId>;
/// Various amounts on deposit for each parachain. An entry in `ManagedIds` implies a non-
/// default entry here.
///
/// The actual amount locked on its behalf at any time is the maximum item in this list. The
/// first item in the list is the amount locked for the current Lease Period. Following
/// items are for the subsequent lease periods.
///
/// The default value (an empty list) implies that the parachain no longer exists (or never
/// existed) as far as this module is concerned.
///
/// If a parachain doesn't exist *yet* but is scheduled to exist in the future, then it
/// will be left-padded with one or more zeroes to denote the fact that nothing is held on
/// deposit for the non-existent chain currently, but is held at some point in the future.
pub Deposits get(deposits): map ParaId => Vec<BalanceOf<T>>;
/// Information relating to the current auction, if there is one.
///
/// The first item in the tuple is the lease period index that the first of the four
/// contiguous lease periods on auction is for. The second is the block number when the
/// auction will "begin to end", i.e. the first block of the Ending Period of the auction.
pub AuctionInfo get(auction_info): Option<(LeasePeriodOf<T>, T::BlockNumber)>;
/// The winning bids for each of the 10 ranges at each block in the final Ending Period of
/// the current auction. The map's key is the 0-based index into the Ending Period. The
/// first block of the ending period is 0; the last is `EndingPeriod - 1`.
pub Winning get(winning): map T::BlockNumber => Option<WinningData<T>>;
/// Amounts currently reserved in the accounts of the bidders currently winning
/// (sub-)ranges.
pub ReservedAmounts get(reserved_amounts): map Bidder<T::AccountId> => Option<BalanceOf<T>>;
/// The set of Para IDs that have won and need to be on-boarded at an upcoming lease-period.
/// This is cleared out on the first block of the lease period.
pub OnboardQueue get(onboard_queue): map LeasePeriodOf<T> => Vec<ParaId>;
/// The actual on-boarding information. Only exists when one of the following is true:
/// - It is before the lease period that the parachain should be on-boarded.
/// - The full on-boarding information has not yet been provided and the parachain is not
/// yet due to be off-boarded.
pub Onboarding get(onboarding): map ParaId =>
Option<(LeasePeriodOf<T>, IncomingParachain<T::AccountId, T::Hash>)>;
/// Off-boarding account; currency held on deposit for the parachain gets placed here if the
/// parachain gets off-boarded; i.e. its lease period is up and it isn't renewed.
pub Offboarding get(offboarding): map ParaId => T::AccountId;
}
}
impl<T: Trait> SwapAux for Module<T> {
fn ensure_can_swap(one: ParaId, other: ParaId) -> Result<(), &'static str> {
if <Onboarding<T>>::exists(one) || <Onboarding<T>>::exists(other) {
Err("can't swap an undeployed parachain")?
}
Ok(())
}
fn on_swap(one: ParaId, other: ParaId) -> Result<(), &'static str> {
<Offboarding<T>>::swap(one, other);
<Deposits<T>>::swap(one, other);
ManagedIds::mutate(|ids| swap_ordered_existence(ids, one, other));
Ok(())
}
}
decl_event!(
pub enum Event<T> where
Loading full blame...