slots.rs 53.2 KiB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
// 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 sr_primitives::traits::{CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash};
use sr_primitives::weights::SimpleDispatchInfo;
use codec::{Encode, Decode};
use srml_support::{
	decl_module, decl_storage, decl_event, StorageValue, StorageMap, ensure,
	traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get}
};
Gavin Wood's avatar
Gavin Wood committed
use primitives::parachain::AccountIdConversion;
use crate::parachains::ParachainRegistrar;
use system::{ensure_signed, ensure_root};
Gavin Wood's avatar
Gavin Wood committed
use crate::slot_range::{SlotRange, SLOT_RANGE_COUNT};

type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
type ParaIdOf<T> = <<T as Trait>::Parachains as ParachainRegistrar<<T as system::Trait>::AccountId>>::ParaId;

/// 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: ParachainRegistrar<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>;
}

/// 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.
	who: AccountId,
	/// An additional ID to allow the same account ID (and funding source) to have multiple
	/// logical bidders.
	sub: SubId,
}

/// The desired target of a bidder in an auction.
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Bidder<AccountId, ParaId> {
	/// 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, ParaId: AccountIdConversion<AccountId>> Bidder<AccountId, ParaId> {
	/// 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, ParaIdOf<T>>, 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>>, ParaIdOf<T>, BalanceOf<T>, SlotRange)>;

// This module's storage items.
Gavin Wood's avatar
Gavin Wood committed
decl_storage! {
	trait Store for Module<T: Trait> as Slots {

		/// The number of auctions that been started so far.
		pub AuctionCounter get(auction_counter): AuctionIndex;

		/// 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<ParaIdOf<T>>;

		/// 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 ParaIdOf<T> => 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, ParaIdOf<T>> => 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<ParaIdOf<T>>;

		/// 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 ParaIdOf<T> =>
			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 ParaIdOf<T> => T::AccountId;
	}
}

decl_event!(
	pub enum Event<T> where
		AccountId = <T as system::Trait>::AccountId,
		BlockNumber = <T as system::Trait>::BlockNumber,
		LeasePeriod = LeasePeriodOf<T>,
		ParaId = ParaIdOf<T>,
		Balance = BalanceOf<T>,
	{
		/// A new lease period is beginning.
		NewLeasePeriod(LeasePeriod),
		/// An auction started. Provides its index and the block number where it will begin to
		/// close and the first lease period of the quadruplet that is auctioned.
		AuctionStarted(AuctionIndex, LeasePeriod, BlockNumber),
		/// An auction ended. All funds become unreserved.
		AuctionClosed(AuctionIndex),
		/// Someone won the right to deploy a parachain. Balance amount is deducted for deposit.
		WonDeploy(NewBidder<AccountId>, SlotRange, ParaId, Balance),
		/// An existing parachain won the right to continue.
		WonRenewal(ParaId, SlotRange, Balance, Balance),
		/// Funds were reserved for a winning bid. First balance is the extra amount reserved.
		/// Second is the total.
		Reserved(AccountId, Balance, Balance),
		/// Funds were unreserved since bidder is no longer active.
		Unreserved(AccountId, Balance),
Loading full blame...