mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 12:51:02 +00:00
Introduce Parathreads (runtime) (#341)
* Rest of parathread draft implementation, parachain permissioning. * Update Substrate * Update Substrate again * Integrate weight/fee stuff. * Council * Build fixes * More fixes * Minor additions * fix some small errors * Revert "fix some small errors" This reverts commit 4fb52c82adfdaf3af98edfe36b280133bcd4f9d3. * Merge fix. * do_swap -> on_swap * Update depdendency to polkadot-master * Fix more merge problems * Some patching of errors * Fix storage closure * Actually fix storage. It builds! * Tests run... but not successfully. * Add `run_to_block` to get parachains active to start * More `run_to_block` * Fix build * Queue up changes to threads * Move registration test * Fix regsiter/deregister test * Retry queue. * Minor refactor * Refactor to avoid heavy storage items * Make tests pass * remove para on deregister, add events * Remove println * Fix register/deregister parathread test * fix merge * Parathread can be activated test * Test auction * Add `Debtors` storage item I considered putting the debtor information in `ParaInfo`, but it did not make sense to me since this information only applies to parathreads, not `paras` in general. * remove comment code * Some new tests * Fixes for removing threads when scheduled. Tests. * Test progression of threads. * Test that reschedule queuing works properly. * Make test slightly more interesting * whitespace * Swap works properly. * Update locks * Build * Rename can_swap * Add test for funds to be correctly returned after a swap Swap does not seem to have logic which correctly swaps the debtor account to the new parathread. * Make tests consistant * Add check that `PendingSwap` is cleaned up * Update runtime/src/parachains.rs Co-Authored-By: Robert Habermeier <rphmeier@gmail.com> * Update runtime/src/registrar.rs Co-Authored-By: Robert Habermeier <rphmeier@gmail.com> * Some fixes/suggestions from review * Docs * Apply suggestions from code review Co-Authored-By: Robert Habermeier <rphmeier@gmail.com> Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com> * Update network/src/gossip.rs Co-Authored-By: Robert Habermeier <rphmeier@gmail.com> * Rename OnSwap * Add missing `]` * Rejig ordering semantics, making everything a bit slower but correct. * Some Fixes to Parathread Compile (#470) * Some Fixes * Fix queue_upward_messages * Change back to const * Build fixes * Fix tests
This commit is contained in:
Generated
+2
@@ -2773,6 +2773,7 @@ dependencies = [
|
|||||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sr-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
"sr-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
|
"substrate-primitives 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
"tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -2805,6 +2806,7 @@ dependencies = [
|
|||||||
"libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"polkadot-parachain 0.6.0",
|
||||||
"polkadot-primitives 0.6.0",
|
"polkadot-primitives 0.6.0",
|
||||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@@ -265,7 +265,8 @@ impl<F, P> ChainContext for (F, P) where
|
|||||||
let leaf_id = BlockId::Hash(leaf);
|
let leaf_id = BlockId::Hash(leaf);
|
||||||
let active_parachains = api.active_parachains(&leaf_id)?;
|
let active_parachains = api.active_parachains(&leaf_id)?;
|
||||||
|
|
||||||
for para_id in active_parachains {
|
// TODO: https://github.com/paritytech/polkadot/issues/467
|
||||||
|
for (para_id, _) in active_parachains {
|
||||||
if let Some(ingress) = api.ingress(&leaf_id, para_id, None)? {
|
if let Some(ingress) = api.ingress(&leaf_id, para_id, None)? {
|
||||||
for (_height, _from, queue_root) in ingress.iter() {
|
for (_height, _from, queue_root) in ingress.iter() {
|
||||||
with_queue_root(queue_root);
|
with_queue_root(queue_root);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use polkadot_primitives::{Block, BlockNumber, Hash, Header, BlockId};
|
|||||||
use polkadot_primitives::parachain::{
|
use polkadot_primitives::parachain::{
|
||||||
Id as ParaId, Chain, DutyRoster, ParachainHost, TargetedMessage,
|
Id as ParaId, Chain, DutyRoster, ParachainHost, TargetedMessage,
|
||||||
ValidatorId, StructuredUnroutedIngress, BlockIngressRoots, Status,
|
ValidatorId, StructuredUnroutedIngress, BlockIngressRoots, Status,
|
||||||
FeeSchedule, HeadData,
|
FeeSchedule, HeadData, Retriable, CollatorId
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use substrate_client::error::Result as ClientResult;
|
use substrate_client::error::Result as ClientResult;
|
||||||
@@ -177,7 +177,7 @@ impl NetworkService for TestNetwork {
|
|||||||
struct ApiData {
|
struct ApiData {
|
||||||
validators: Vec<ValidatorId>,
|
validators: Vec<ValidatorId>,
|
||||||
duties: Vec<Chain>,
|
duties: Vec<Chain>,
|
||||||
active_parachains: Vec<ParaId>,
|
active_parachains: Vec<(ParaId, Option<(CollatorId, Retriable)>)>,
|
||||||
ingress: HashMap<ParaId, StructuredUnroutedIngress>,
|
ingress: HashMap<ParaId, StructuredUnroutedIngress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ impl ParachainHost<Block> for RuntimeApi {
|
|||||||
_: ExecutionContext,
|
_: ExecutionContext,
|
||||||
_: Option<()>,
|
_: Option<()>,
|
||||||
_: Vec<u8>,
|
_: Vec<u8>,
|
||||||
) -> ClientResult<NativeOrEncoded<Vec<ParaId>>> {
|
) -> ClientResult<NativeOrEncoded<Vec<(ParaId, Option<(CollatorId, Retriable)>)>>> {
|
||||||
Ok(NativeOrEncoded::Native(self.data.lock().active_parachains.clone()))
|
Ok(NativeOrEncoded::Native(self.data.lock().active_parachains.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ wasmi = { version = "0.4.3", optional = true }
|
|||||||
derive_more = { version = "0.14", optional = true }
|
derive_more = { version = "0.14", optional = true }
|
||||||
serde = { version = "1.0", default-features = false, features = [ "derive" ] }
|
serde = { version = "1.0", default-features = false, features = [ "derive" ] }
|
||||||
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
||||||
|
substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
||||||
lazy_static = { version = "1.3.0", optional = true }
|
lazy_static = { version = "1.3.0", optional = true }
|
||||||
parking_lot = { version = "0.7.1", optional = true }
|
parking_lot = { version = "0.7.1", optional = true }
|
||||||
log = { version = "0.4.6", optional = true }
|
log = { version = "0.4.6", optional = true }
|
||||||
@@ -33,6 +34,7 @@ std = [
|
|||||||
"serde/std",
|
"serde/std",
|
||||||
"rstd/std",
|
"rstd/std",
|
||||||
"shared_memory",
|
"shared_memory",
|
||||||
|
"substrate-primitives/std",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"log"
|
"log"
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub mod wasm_api;
|
|||||||
use rstd::vec::Vec;
|
use rstd::vec::Vec;
|
||||||
|
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
|
use substrate_primitives::TypeId;
|
||||||
|
|
||||||
/// Validation parameters for evaluating the parachain validity function.
|
/// Validation parameters for evaluating the parachain validity function.
|
||||||
// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
|
// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
|
||||||
@@ -82,6 +83,16 @@ pub struct ValidationResult {
|
|||||||
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Debug))]
|
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Debug))]
|
||||||
pub struct Id(u32);
|
pub struct Id(u32);
|
||||||
|
|
||||||
|
impl TypeId for Id {
|
||||||
|
const TYPE_ID: [u8; 4] = *b"para";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type for determining the active set of parachains.
|
||||||
|
pub trait ActiveThreads {
|
||||||
|
/// Return the current ordered set of `Id`s of active parathreads.
|
||||||
|
fn active_threads() -> Vec<Id>;
|
||||||
|
}
|
||||||
|
|
||||||
impl codec::CompactAs for Id {
|
impl codec::CompactAs for Id {
|
||||||
type As = u32;
|
type As = u32;
|
||||||
fn encode_as(&self) -> &u32 {
|
fn encode_as(&self) -> &u32 {
|
||||||
@@ -105,11 +116,19 @@ impl From<u32> for Id {
|
|||||||
fn from(x: u32) -> Self { Id(x) }
|
fn from(x: u32) -> Self { Id(x) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const USER_INDEX_START: u32 = 1000;
|
||||||
|
|
||||||
|
/// The ID of the first user (non-system) parachain.
|
||||||
|
pub const LOWEST_USER_ID: Id = Id(USER_INDEX_START);
|
||||||
|
|
||||||
impl Id {
|
impl Id {
|
||||||
/// Convert this Id into its inner representation.
|
/// Convert this Id into its inner representation.
|
||||||
pub fn into_inner(self) -> u32 {
|
pub fn into_inner(self) -> u32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this parachain runs with system-level privileges.
|
||||||
|
pub fn is_system(&self) -> bool { self.0 < USER_INDEX_START }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove all of this, move sr-primitives::AccountIdConversion to own crate and and use that.
|
// TODO: Remove all of this, move sr-primitives::AccountIdConversion to own crate and and use that.
|
||||||
@@ -191,6 +210,9 @@ pub enum ParachainDispatchOrigin {
|
|||||||
/// As the special `Origin::Parachain(ParaId)`. This is good when interacting with parachain-
|
/// As the special `Origin::Parachain(ParaId)`. This is good when interacting with parachain-
|
||||||
/// aware modules which need to succinctly verify that the origin is a parachain.
|
/// aware modules which need to succinctly verify that the origin is a parachain.
|
||||||
Parachain,
|
Parachain,
|
||||||
|
/// As the simple, superuser `Origin::Root`. This can only be done on specially permissioned
|
||||||
|
/// parachains.
|
||||||
|
Root,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl rstd::convert::TryFrom<u8> for ParachainDispatchOrigin {
|
impl rstd::convert::TryFrom<u8> for ParachainDispatchOrigin {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use primitives::bytes;
|
|||||||
use application_crypto::KeyTypeId;
|
use application_crypto::KeyTypeId;
|
||||||
|
|
||||||
pub use polkadot_parachain::{
|
pub use polkadot_parachain::{
|
||||||
Id, AccountIdConversion, ParachainDispatchOrigin, UpwardMessage,
|
Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The key type ID for a collator key.
|
/// The key type ID for a collator key.
|
||||||
@@ -78,6 +78,67 @@ pub type ValidatorPair = validator_app::Pair;
|
|||||||
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
|
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
|
||||||
pub type ValidatorSignature = validator_app::Signature;
|
pub type ValidatorSignature = validator_app::Signature;
|
||||||
|
|
||||||
|
/// Retriability for a given active para.
|
||||||
|
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
|
pub enum Retriable {
|
||||||
|
/// Ineligible for retry. This means it's either a parachain which is always scheduled anyway or
|
||||||
|
/// has been removed/swapped.
|
||||||
|
Never,
|
||||||
|
/// Eligible for retry; the associated value is the number of retries that the para already had.
|
||||||
|
WithRetries(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type determining the active set of parachains in current block.
|
||||||
|
pub trait ActiveParas {
|
||||||
|
/// Return the active set of parachains in current block. This attempts to keep any IDs in the
|
||||||
|
/// same place between sequential blocks. It is therefore unordered. The second item in the
|
||||||
|
/// tuple is the required collator ID, if any. If `Some`, then it is invalid to include any
|
||||||
|
/// other collator's block.
|
||||||
|
///
|
||||||
|
/// NOTE: The initial implementation simply concatenates the (ordered) set of (permanent)
|
||||||
|
/// parachain IDs with the (unordered) set of parathread IDs selected for this block.
|
||||||
|
fn active_paras() -> Vec<(Id, Option<(CollatorId, Retriable)>)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Description of how often/when this parachain is scheduled for progression.
|
||||||
|
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
|
pub enum Scheduling {
|
||||||
|
/// Scheduled every block.
|
||||||
|
Always,
|
||||||
|
/// Scheduled dynamically (i.e. a parathread).
|
||||||
|
Dynamic,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information regarding a deployed parachain/thread.
|
||||||
|
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
|
pub struct Info {
|
||||||
|
/// Scheduling info.
|
||||||
|
pub scheduling: Scheduling,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An `Info` value for a standard leased parachain.
|
||||||
|
pub const PARACHAIN_INFO: Info = Info {
|
||||||
|
scheduling: Scheduling::Always,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Auxilliary for when there's an attempt to swapped two parachains/parathreads.
|
||||||
|
pub trait SwapAux {
|
||||||
|
/// Result describing whether it is possible to swap two parachains. Doesn't mutate state.
|
||||||
|
fn ensure_can_swap(one: Id, other: Id) -> Result<(), &'static str>;
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// May only be called on a state that `ensure_can_swap` has previously returned `Ok` for: if this is
|
||||||
|
/// not the case, the result is undefined. May only return an error if `ensure_can_swap` also returns
|
||||||
|
/// an error.
|
||||||
|
fn on_swap(one: Id, other: Id) -> Result<(), &'static str>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Identifier for a chain, either one of a number of parachains or the relay chain.
|
/// Identifier for a chain, either one of a number of parachains or the relay chain.
|
||||||
#[derive(Copy, Clone, PartialEq, Encode, Decode)]
|
#[derive(Copy, Clone, PartialEq, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
@@ -432,7 +493,7 @@ substrate_client::decl_runtime_apis! {
|
|||||||
/// Get the current duty roster.
|
/// Get the current duty roster.
|
||||||
fn duty_roster() -> DutyRoster;
|
fn duty_roster() -> DutyRoster;
|
||||||
/// Get the currently active parachains.
|
/// Get the currently active parachains.
|
||||||
fn active_parachains() -> Vec<Id>;
|
fn active_parachains() -> Vec<(Id, Option<(CollatorId, Retriable)>)>;
|
||||||
/// Get the given parachain's status.
|
/// Get the given parachain's status.
|
||||||
fn parachain_status(id: Id) -> Option<Status>;
|
fn parachain_status(id: Id) -> Option<Status>;
|
||||||
/// Get the given parachain's head code blob.
|
/// Get the given parachain's head code blob.
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ timestamp = { package = "srml-timestamp", git = "https://github.com/paritytech/s
|
|||||||
treasury = { package = "srml-treasury", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
|
treasury = { package = "srml-treasury", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
|
||||||
|
|
||||||
primitives = { package = "polkadot-primitives", path = "../primitives", default-features = false }
|
primitives = { package = "polkadot-primitives", path = "../primitives", default-features = false }
|
||||||
|
polkadot-parachain = { path = "../parachain", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex-literal = "0.2.0"
|
hex-literal = "0.2.0"
|
||||||
@@ -79,6 +80,7 @@ std = [
|
|||||||
"codec/std",
|
"codec/std",
|
||||||
"inherents/std",
|
"inherents/std",
|
||||||
"substrate-primitives/std",
|
"substrate-primitives/std",
|
||||||
|
"polkadot-parachain/std",
|
||||||
"client/std",
|
"client/std",
|
||||||
"offchain-primitives/std",
|
"offchain-primitives/std",
|
||||||
"rstd/std",
|
"rstd/std",
|
||||||
|
|||||||
@@ -77,14 +77,16 @@ use sr_primitives::{ModuleId, weights::SimpleDispatchInfo,
|
|||||||
use crate::slots;
|
use crate::slots;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use rstd::vec::Vec;
|
use rstd::vec::Vec;
|
||||||
use crate::parachains::ParachainRegistrar;
|
|
||||||
use substrate_primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX;
|
use substrate_primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX;
|
||||||
|
use primitives::parachain::Id as ParaId;
|
||||||
|
|
||||||
const MODULE_ID: ModuleId = ModuleId(*b"py/cfund");
|
const MODULE_ID: ModuleId = ModuleId(*b"py/cfund");
|
||||||
|
|
||||||
pub type BalanceOf<T> = <<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
|
pub type BalanceOf<T> =
|
||||||
pub type NegativeImbalanceOf<T> = <<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
|
<<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
|
||||||
pub type ParaIdOf<T> = <<T as slots::Trait>::Parachains as ParachainRegistrar<<T as system::Trait>::AccountId>>::ParaId;
|
#[allow(dead_code)]
|
||||||
|
pub type NegativeImbalanceOf<T> =
|
||||||
|
<<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
|
||||||
|
|
||||||
pub trait Trait: slots::Trait {
|
pub trait Trait: slots::Trait {
|
||||||
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
|
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
|
||||||
@@ -117,7 +119,7 @@ pub enum LastContribution<BlockNumber> {
|
|||||||
|
|
||||||
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
pub struct FundInfo<AccountId, Balance, Hash, BlockNumber, ParaId> {
|
pub struct FundInfo<AccountId, Balance, Hash, BlockNumber> {
|
||||||
/// The parachain that this fund has funded, if there is one. As long as this is `Some`, then
|
/// The parachain that this fund has funded, if there is one. As long as this is `Some`, then
|
||||||
/// the funds may not be withdrawn and the fund cannot be dissolved.
|
/// the funds may not be withdrawn and the fund cannot be dissolved.
|
||||||
parachain: Option<ParaId>,
|
parachain: Option<ParaId>,
|
||||||
@@ -154,7 +156,7 @@ decl_storage! {
|
|||||||
trait Store for Module<T: Trait> as Example {
|
trait Store for Module<T: Trait> as Example {
|
||||||
/// Info on all of the funds.
|
/// Info on all of the funds.
|
||||||
Funds get(funds):
|
Funds get(funds):
|
||||||
map FundIndex => Option<FundInfo<T::AccountId, BalanceOf<T>, T::Hash, T::BlockNumber, ParaIdOf<T>>>;
|
map FundIndex => Option<FundInfo<T::AccountId, BalanceOf<T>, T::Hash, T::BlockNumber>>;
|
||||||
|
|
||||||
/// The total number of funds that have so far been allocated.
|
/// The total number of funds that have so far been allocated.
|
||||||
FundCount get(fund_count): FundIndex;
|
FundCount get(fund_count): FundIndex;
|
||||||
@@ -172,7 +174,6 @@ decl_event! {
|
|||||||
pub enum Event<T> where
|
pub enum Event<T> where
|
||||||
<T as system::Trait>::AccountId,
|
<T as system::Trait>::AccountId,
|
||||||
Balance = BalanceOf<T>,
|
Balance = BalanceOf<T>,
|
||||||
ParaId = ParaIdOf<T>,
|
|
||||||
{
|
{
|
||||||
Created(FundIndex),
|
Created(FundIndex),
|
||||||
Contributed(AccountId, FundIndex, Balance),
|
Contributed(AccountId, FundIndex, Balance),
|
||||||
@@ -321,7 +322,7 @@ decl_module! {
|
|||||||
/// - `para_id` is the parachain index that this fund won.
|
/// - `para_id` is the parachain index that this fund won.
|
||||||
fn onboard(origin,
|
fn onboard(origin,
|
||||||
#[compact] index: FundIndex,
|
#[compact] index: FundIndex,
|
||||||
#[compact] para_id: ParaIdOf<T>
|
#[compact] para_id: ParaId
|
||||||
) {
|
) {
|
||||||
let _ = ensure_signed(origin)?;
|
let _ = ensure_signed(origin)?;
|
||||||
|
|
||||||
@@ -503,13 +504,14 @@ mod tests {
|
|||||||
use srml_support::{impl_outer_origin, assert_ok, assert_noop, parameter_types};
|
use srml_support::{impl_outer_origin, assert_ok, assert_noop, parameter_types};
|
||||||
use sr_io::with_externalities;
|
use sr_io::with_externalities;
|
||||||
use substrate_primitives::{H256, Blake2Hasher};
|
use substrate_primitives::{H256, Blake2Hasher};
|
||||||
use primitives::parachain::Id as ParaId;
|
use primitives::parachain::Info as ParaInfo;
|
||||||
// The testing primitives are very useful for avoiding having to work with signatures
|
// The testing primitives are very useful for avoiding having to work with signatures
|
||||||
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried.
|
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried.
|
||||||
use sr_primitives::{
|
use sr_primitives::{
|
||||||
Perbill, Permill, testing::Header,
|
Perbill, Permill, testing::Header,
|
||||||
traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup, ConvertInto},
|
traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup, ConvertInto},
|
||||||
};
|
};
|
||||||
|
use crate::registrar::Registrar;
|
||||||
|
|
||||||
impl_outer_origin! {
|
impl_outer_origin! {
|
||||||
pub enum Origin for Test {}
|
pub enum Origin for Test {}
|
||||||
@@ -595,16 +597,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestParachains;
|
pub struct TestParachains;
|
||||||
impl ParachainRegistrar<u64> for TestParachains {
|
impl Registrar<u64> for TestParachains {
|
||||||
type ParaId = ParaId;
|
fn new_id() -> ParaId {
|
||||||
fn new_id() -> Self::ParaId {
|
|
||||||
PARACHAIN_COUNT.with(|p| {
|
PARACHAIN_COUNT.with(|p| {
|
||||||
*p.borrow_mut() += 1;
|
*p.borrow_mut() += 1;
|
||||||
(*p.borrow() - 1).into()
|
(*p.borrow() - 1).into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn register_parachain(
|
fn register_para(
|
||||||
id: Self::ParaId,
|
id: ParaId,
|
||||||
|
_info: ParaInfo,
|
||||||
code: Vec<u8>,
|
code: Vec<u8>,
|
||||||
initial_head_data: Vec<u8>
|
initial_head_data: Vec<u8>
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
@@ -616,7 +618,7 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn deregister_parachain(id: Self::ParaId) -> Result<(), &'static str> {
|
fn deregister_para(id: ParaId) -> Result<(), &'static str> {
|
||||||
PARACHAINS.with(|p| {
|
PARACHAINS.with(|p| {
|
||||||
if !p.borrow().contains_key(&id.into_inner()) {
|
if !p.borrow().contains_key(&id.into_inner()) {
|
||||||
panic!("ID doesn't exist")
|
panic!("ID doesn't exist")
|
||||||
|
|||||||
+31
-11
@@ -24,15 +24,16 @@ mod attestations;
|
|||||||
mod claims;
|
mod claims;
|
||||||
mod parachains;
|
mod parachains;
|
||||||
mod slot_range;
|
mod slot_range;
|
||||||
|
mod registrar;
|
||||||
mod slots;
|
mod slots;
|
||||||
mod crowdfund;
|
mod crowdfund;
|
||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
use codec::{Encode, Decode};
|
|
||||||
use substrate_primitives::u32_trait::{_1, _2, _3, _4};
|
use substrate_primitives::u32_trait::{_1, _2, _3, _4};
|
||||||
|
use codec::{Encode, Decode};
|
||||||
use primitives::{
|
use primitives::{
|
||||||
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
|
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
|
||||||
parachain, ValidityError,
|
parachain::{self, ActiveParas}, ValidityError,
|
||||||
};
|
};
|
||||||
use client::{
|
use client::{
|
||||||
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
|
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
|
||||||
@@ -187,7 +188,7 @@ impl indices::Trait for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const ExistentialDeposit: Balance = 10 * CENTS;
|
pub const ExistentialDeposit: Balance = 100 * CENTS;
|
||||||
pub const TransferFee: Balance = 1 * CENTS;
|
pub const TransferFee: Balance = 1 * CENTS;
|
||||||
pub const CreationFee: Balance = 1 * CENTS;
|
pub const CreationFee: Balance = 1 * CENTS;
|
||||||
pub const TransactionBaseFee: Balance = 1 * CENTS;
|
pub const TransactionBaseFee: Balance = 1 * CENTS;
|
||||||
@@ -221,7 +222,6 @@ impl balances::Trait for Runtime {
|
|||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
|
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl timestamp::Trait for Runtime {
|
impl timestamp::Trait for Runtime {
|
||||||
type Moment = u64;
|
type Moment = u64;
|
||||||
type OnTimestampSet = Babe;
|
type OnTimestampSet = Babe;
|
||||||
@@ -275,15 +275,15 @@ impl session::Trait for Runtime {
|
|||||||
type ShouldEndSession = Babe;
|
type ShouldEndSession = Babe;
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
type Keys = SessionKeys;
|
type Keys = SessionKeys;
|
||||||
type SelectInitialValidators = Staking;
|
|
||||||
type ValidatorId = AccountId;
|
type ValidatorId = AccountId;
|
||||||
type ValidatorIdOf = staking::StashOf<Self>;
|
type ValidatorIdOf = staking::StashOf<Self>;
|
||||||
|
type SelectInitialValidators = Staking;
|
||||||
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
|
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl session::historical::Trait for Runtime {
|
impl session::historical::Trait for Runtime {
|
||||||
type FullIdentification = staking::Exposure<AccountId, Balance>;
|
type FullIdentification = staking::Exposure<AccountId, Balance>;
|
||||||
type FullIdentificationOf = staking::ExposureOf<Self>;
|
type FullIdentificationOf = staking::ExposureOf<Runtime>;
|
||||||
}
|
}
|
||||||
|
|
||||||
srml_staking_reward_curve::build! {
|
srml_staking_reward_curve::build! {
|
||||||
@@ -480,6 +480,24 @@ impl parachains::Trait for Runtime {
|
|||||||
type Origin = Origin;
|
type Origin = Origin;
|
||||||
type Call = Call;
|
type Call = Call;
|
||||||
type ParachainCurrency = Balances;
|
type ParachainCurrency = Balances;
|
||||||
|
type ActiveParachains = Registrar;
|
||||||
|
type Registrar = Registrar;
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub const ParathreadDeposit: Balance = 500 * DOLLARS;
|
||||||
|
pub const QueueSize: usize = 2;
|
||||||
|
pub const MaxRetries: u32 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl registrar::Trait for Runtime {
|
||||||
|
type Event = Event;
|
||||||
|
type Origin = Origin;
|
||||||
|
type Currency = Balances;
|
||||||
|
type ParathreadDeposit = ParathreadDeposit;
|
||||||
|
type SwapAux = Slots;
|
||||||
|
type QueueSize = QueueSize;
|
||||||
|
type MaxRetries = MaxRetries;
|
||||||
}
|
}
|
||||||
|
|
||||||
parameter_types!{
|
parameter_types!{
|
||||||
@@ -489,8 +507,8 @@ parameter_types!{
|
|||||||
|
|
||||||
impl slots::Trait for Runtime {
|
impl slots::Trait for Runtime {
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
type Currency = balances::Module<Self>;
|
type Currency = Balances;
|
||||||
type Parachains = parachains::Module<Self>;
|
type Parachains = Registrar;
|
||||||
type LeasePeriod = LeasePeriod;
|
type LeasePeriod = LeasePeriod;
|
||||||
type EndingPeriod = EndingPeriod;
|
type EndingPeriod = EndingPeriod;
|
||||||
}
|
}
|
||||||
@@ -553,9 +571,10 @@ construct_runtime!(
|
|||||||
|
|
||||||
// Parachains stuff; slots are disabled (no auctions initially). The rest are safe as they
|
// Parachains stuff; slots are disabled (no auctions initially). The rest are safe as they
|
||||||
// have no public dispatchables.
|
// have no public dispatchables.
|
||||||
Parachains: parachains::{Module, Call, Storage, Config<T>, Inherent, Origin},
|
Parachains: parachains::{Module, Call, Storage, Config, Inherent, Origin},
|
||||||
Attestations: attestations::{Module, Call, Storage},
|
Attestations: attestations::{Module, Call, Storage},
|
||||||
Slots: slots::{Module, Call, Storage, Event<T>},
|
Slots: slots::{Module, Call, Storage, Event<T>},
|
||||||
|
Registrar: registrar::{Module, Call, Storage, Event, Config<T>},
|
||||||
|
|
||||||
// Sudo. Usable initially.
|
// Sudo. Usable initially.
|
||||||
// RELEASE: remove this for release build.
|
// RELEASE: remove this for release build.
|
||||||
@@ -583,6 +602,7 @@ pub type SignedExtra = (
|
|||||||
system::CheckNonce<Runtime>,
|
system::CheckNonce<Runtime>,
|
||||||
system::CheckWeight<Runtime>,
|
system::CheckWeight<Runtime>,
|
||||||
balances::TakeFees<Runtime>,
|
balances::TakeFees<Runtime>,
|
||||||
|
registrar::LimitParathreadCommits<Runtime>
|
||||||
);
|
);
|
||||||
/// Unchecked extrinsic type as expected by this runtime.
|
/// Unchecked extrinsic type as expected by this runtime.
|
||||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
||||||
@@ -653,8 +673,8 @@ impl_runtime_apis! {
|
|||||||
fn duty_roster() -> parachain::DutyRoster {
|
fn duty_roster() -> parachain::DutyRoster {
|
||||||
Parachains::calculate_duty_roster().0
|
Parachains::calculate_duty_roster().0
|
||||||
}
|
}
|
||||||
fn active_parachains() -> Vec<parachain::Id> {
|
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
||||||
Parachains::active_parachains()
|
Registrar::active_paras()
|
||||||
}
|
}
|
||||||
fn parachain_status(id: parachain::Id) -> Option<parachain::Status> {
|
fn parachain_status(id: parachain::Id) -> Option<parachain::Status> {
|
||||||
Parachains::parachain_status(&id)
|
Parachains::parachain_status(&id)
|
||||||
|
|||||||
+297
-212
@@ -17,17 +17,20 @@
|
|||||||
//! Main parachains logic. For now this is just the determination of which validators do what.
|
//! Main parachains logic. For now this is just the determination of which validators do what.
|
||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
|
use rstd::result;
|
||||||
use rstd::collections::btree_map::BTreeMap;
|
use rstd::collections::btree_map::BTreeMap;
|
||||||
use codec::{Encode, Decode, HasCompact};
|
use codec::{Encode, Decode};
|
||||||
use srml_support::{decl_storage, decl_module, fail, ensure};
|
use srml_support::{decl_storage, decl_module, ensure};
|
||||||
|
|
||||||
use sr_primitives::traits::{
|
use sr_primitives::traits::{
|
||||||
Hash as HashT, BlakeTwo256, Member, CheckedConversion, Saturating, One, Zero, Dispatchable,
|
Hash as HashT, BlakeTwo256, Saturating, One, Zero, Dispatchable,
|
||||||
|
AccountIdConversion,
|
||||||
};
|
};
|
||||||
use sr_primitives::weights::SimpleDispatchInfo;
|
use sr_primitives::weights::SimpleDispatchInfo;
|
||||||
use primitives::{Hash, Balance, parachain::{
|
use primitives::{Hash, Balance, parachain::{
|
||||||
self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, AccountIdConversion,
|
self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement,
|
||||||
ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots, ValidatorId
|
ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots, ValidatorId, ActiveParas, CollatorId,
|
||||||
|
Retriable
|
||||||
}};
|
}};
|
||||||
use {system, session};
|
use {system, session};
|
||||||
use srml_support::{
|
use srml_support::{
|
||||||
@@ -36,11 +39,9 @@ use srml_support::{
|
|||||||
|
|
||||||
use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};
|
use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", test))]
|
use system::ensure_none;
|
||||||
use rstd::marker::PhantomData;
|
|
||||||
|
|
||||||
use system::{ensure_none, ensure_root};
|
|
||||||
use crate::attestations::{self, IncludedBlocks};
|
use crate::attestations::{self, IncludedBlocks};
|
||||||
|
use crate::registrar::Registrar;
|
||||||
|
|
||||||
// ranges for iteration of general block number don't work, so this
|
// ranges for iteration of general block number don't work, so this
|
||||||
// is a utility to get around that.
|
// is a utility to get around that.
|
||||||
@@ -68,75 +69,6 @@ fn number_range<N>(low: N, high: N) -> BlockNumberRange<N> {
|
|||||||
BlockNumberRange { low, high }
|
BlockNumberRange { low, high }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parachain registration API.
|
|
||||||
pub trait ParachainRegistrar<AccountId> {
|
|
||||||
/// An identifier for a parachain.
|
|
||||||
type ParaId: Member + Parameter + Default + AccountIdConversion<AccountId> + Copy + HasCompact;
|
|
||||||
|
|
||||||
/// Create a new unique parachain identity for later registration.
|
|
||||||
fn new_id() -> Self::ParaId;
|
|
||||||
|
|
||||||
/// Register a parachain with given `code` and `initial_head_data`. `id` must not yet be registered or it will
|
|
||||||
/// result in a error.
|
|
||||||
fn register_parachain(id: Self::ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result;
|
|
||||||
|
|
||||||
/// Deregister a parachain with given `id`. If `id` is not currently registered, an error is returned.
|
|
||||||
fn deregister_parachain(id: Self::ParaId) -> Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Trait> ParachainRegistrar<T::AccountId> for Module<T> {
|
|
||||||
type ParaId = ParaId;
|
|
||||||
fn new_id() -> ParaId {
|
|
||||||
<NextFreeId>::mutate(|n| { let r = *n; *n = ParaId::from(u32::from(*n) + 1); r })
|
|
||||||
}
|
|
||||||
fn register_parachain(id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
|
|
||||||
let mut parachains = Self::active_parachains();
|
|
||||||
match parachains.binary_search(&id) {
|
|
||||||
Ok(_) => fail!("Parachain already exists"),
|
|
||||||
Err(idx) => parachains.insert(idx, id),
|
|
||||||
}
|
|
||||||
|
|
||||||
<Code>::insert(id, code);
|
|
||||||
<Parachains>::put(parachains);
|
|
||||||
<Heads>::insert(id, initial_head_data);
|
|
||||||
|
|
||||||
// Because there are no ordering guarantees that inherents
|
|
||||||
// are applied before regular transactions, a parachain candidate could
|
|
||||||
// be registered before the `UpdateHeads` inherent is processed. If so, messages
|
|
||||||
// could be sent to a parachain in the block it is registered.
|
|
||||||
<Watermarks<T>>::insert(id, <system::Module<T>>::block_number().saturating_sub(One::one()));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn deregister_parachain(id: ParaId) -> Result {
|
|
||||||
let mut parachains = Self::active_parachains();
|
|
||||||
match parachains.binary_search(&id) {
|
|
||||||
Ok(idx) => { parachains.remove(idx); }
|
|
||||||
Err(_) => return Ok(()),
|
|
||||||
}
|
|
||||||
|
|
||||||
<Code>::remove(id);
|
|
||||||
<Heads>::remove(id);
|
|
||||||
|
|
||||||
let watermark = <Watermarks<T>>::take(id);
|
|
||||||
|
|
||||||
// clear all routing entries _to_. But not those _from_.
|
|
||||||
if let Some(watermark) = watermark {
|
|
||||||
let now = <system::Module<T>>::block_number();
|
|
||||||
|
|
||||||
// iterate over all blocks between watermark and now + 1 (since messages might
|
|
||||||
// have already been sent to `id` in this block.
|
|
||||||
for unrouted_block in number_range(watermark, now).map(|n| n.saturating_add(One::one())) {
|
|
||||||
<UnroutedIngress<T>>::remove(&(unrouted_block, id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<Parachains>::put(parachains);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wrapper trait because an associated type of `Currency<Self::AccountId,Balance=Balance>`
|
// wrapper trait because an associated type of `Currency<Self::AccountId,Balance=Balance>`
|
||||||
// doesn't work.`
|
// doesn't work.`
|
||||||
pub trait ParachainCurrency<AccountId> {
|
pub trait ParachainCurrency<AccountId> {
|
||||||
@@ -186,6 +118,12 @@ pub trait Trait: attestations::Trait {
|
|||||||
|
|
||||||
/// Some way of interacting with balances for fees.
|
/// Some way of interacting with balances for fees.
|
||||||
type ParachainCurrency: ParachainCurrency<Self::AccountId>;
|
type ParachainCurrency: ParachainCurrency<Self::AccountId>;
|
||||||
|
|
||||||
|
/// Means to determine what the current set of active parachains are.
|
||||||
|
type ActiveParachains: ActiveParas;
|
||||||
|
|
||||||
|
/// The way that we are able to register parachains.
|
||||||
|
type Registrar: Registrar<Self::AccountId>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Origin for the parachains module.
|
/// Origin for the parachains module.
|
||||||
@@ -213,8 +151,6 @@ decl_storage! {
|
|||||||
trait Store for Module<T: Trait> as Parachains {
|
trait Store for Module<T: Trait> as Parachains {
|
||||||
/// All authorities' keys at the moment.
|
/// All authorities' keys at the moment.
|
||||||
pub Authorities get(authorities) config(authorities): Vec<ValidatorId>;
|
pub Authorities get(authorities) config(authorities): Vec<ValidatorId>;
|
||||||
/// Vector of all parachain IDs.
|
|
||||||
pub Parachains get(active_parachains): Vec<ParaId>;
|
|
||||||
/// The parachains registered at present.
|
/// The parachains registered at present.
|
||||||
pub Code get(parachain_code): map ParaId => Option<Vec<u8>>;
|
pub Code get(parachain_code): map ParaId => Option<Vec<u8>>;
|
||||||
/// The heads of the parachains registered at present.
|
/// The heads of the parachains registered at present.
|
||||||
@@ -237,35 +173,14 @@ decl_storage! {
|
|||||||
/// decoding when checking receipt validity. First item in tuple is the count of messages
|
/// decoding when checking receipt validity. First item in tuple is the count of messages
|
||||||
/// second if the total length (in bytes) of the message payloads.
|
/// second if the total length (in bytes) of the message payloads.
|
||||||
pub RelayDispatchQueueSize: map ParaId => (u32, u32);
|
pub RelayDispatchQueueSize: map ParaId => (u32, u32);
|
||||||
|
/// The ordered list of ParaIds that have a `RelayDispatchQueue` entry.
|
||||||
|
NeedsDispatch: Vec<ParaId>;
|
||||||
|
|
||||||
/// Did the parachain heads get updated in this block?
|
/// Some if the parachain heads get updated in this block, along with the parachain IDs that
|
||||||
DidUpdate: bool;
|
/// did update. Ordered in the same way as `registrar::Active` (i.e. by ParaId).
|
||||||
|
///
|
||||||
/// The next unused ParaId value.
|
/// None if not yet updated.
|
||||||
NextFreeId: ParaId;
|
pub DidUpdate: Option<Vec<ParaId>>;
|
||||||
}
|
|
||||||
add_extra_genesis {
|
|
||||||
config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
|
|
||||||
config(_phdata): PhantomData<T>;
|
|
||||||
build(build::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
fn build<T: Trait>(config: &GenesisConfig<T>) {
|
|
||||||
let mut p = config.parachains.clone();
|
|
||||||
p.sort_unstable_by_key(|&(ref id, _, _)| *id);
|
|
||||||
p.dedup_by_key(|&mut (ref id, _, _)| *id);
|
|
||||||
|
|
||||||
let only_ids: Vec<ParaId> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
|
|
||||||
|
|
||||||
Parachains::put(&only_ids);
|
|
||||||
|
|
||||||
for (id, code, genesis) in p {
|
|
||||||
// no ingress -- a chain cannot be routed to until it is live.
|
|
||||||
Code::insert(&id, &code);
|
|
||||||
Heads::insert(&id, &genesis);
|
|
||||||
<Watermarks<T>>::insert(&id, &T::BlockNumber::zero());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,32 +189,38 @@ decl_module! {
|
|||||||
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
|
||||||
/// Provide candidate receipts for parachains, in ascending order by id.
|
/// Provide candidate receipts for parachains, in ascending order by id.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
||||||
fn set_heads(origin, heads: Vec<AttestedCandidate>) -> Result {
|
pub fn set_heads(origin, heads: Vec<AttestedCandidate>) -> Result {
|
||||||
ensure_none(origin)?;
|
ensure_none(origin)?;
|
||||||
ensure!(!<DidUpdate>::exists(), "Parachain heads must be updated only once in the block");
|
ensure!(!<DidUpdate>::exists(), "Parachain heads must be updated only once in the block");
|
||||||
|
|
||||||
let active_parachains = Self::active_parachains();
|
let active_parachains = Self::active_parachains();
|
||||||
|
|
||||||
let parachain_count = active_parachains.len();
|
let parachain_count = active_parachains.len();
|
||||||
ensure!(heads.len() <= parachain_count, "Too many parachain candidates");
|
ensure!(heads.len() <= parachain_count, "Too many parachain candidates");
|
||||||
|
|
||||||
|
let mut proceeded = Vec::with_capacity(heads.len());
|
||||||
|
|
||||||
if !active_parachains.is_empty() {
|
if !active_parachains.is_empty() {
|
||||||
// perform integrity checks before writing to storage.
|
// perform integrity checks before writing to storage.
|
||||||
{
|
{
|
||||||
let mut last_id = None;
|
let mut last_id = None;
|
||||||
|
|
||||||
let mut iter = active_parachains.iter();
|
let mut iter = active_parachains.iter();
|
||||||
for head in &heads {
|
for head in &heads {
|
||||||
let id = head.parachain_index();
|
let id = head.parachain_index();
|
||||||
// proposed heads must be ascending order by parachain ID without duplicate.
|
// proposed heads must be ascending order by parachain ID without duplicate.
|
||||||
ensure!(
|
ensure!(
|
||||||
last_id.as_ref().map_or(true, |x| x < &id),
|
last_id.as_ref().map_or(true, |x| x < &id),
|
||||||
"Parachain candidates out of order by ID"
|
"candidate out of order"
|
||||||
);
|
);
|
||||||
|
|
||||||
// must be unknown since active parachains are always sorted.
|
// must be unknown since active parachains are always sorted.
|
||||||
ensure!(
|
let (_, maybe_required_collator) = iter.find(|para| para.0 == id)
|
||||||
iter.find(|x| x == &&id).is_some(),
|
.ok_or("candidate for unregistered parachain {}")?;
|
||||||
"Submitted candidate for unregistered or out-of-order parachain {}"
|
|
||||||
);
|
if let Some((required_collator, _)) = maybe_required_collator {
|
||||||
|
ensure!(required_collator == &head.candidate.collator, "invalid collator");
|
||||||
|
}
|
||||||
|
|
||||||
Self::check_upward_messages(
|
Self::check_upward_messages(
|
||||||
id,
|
id,
|
||||||
@@ -309,7 +230,9 @@ decl_module! {
|
|||||||
)?;
|
)?;
|
||||||
Self::check_egress_queue_roots(&head, &active_parachains)?;
|
Self::check_egress_queue_roots(&head, &active_parachains)?;
|
||||||
|
|
||||||
last_id = Some(head.parachain_index());
|
let id = head.parachain_index();
|
||||||
|
proceeded.push(id);
|
||||||
|
last_id = Some(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,36 +247,23 @@ decl_module! {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Self::dispatch_upward_messages(
|
Self::dispatch_upward_messages(
|
||||||
current_number,
|
|
||||||
&active_parachains,
|
|
||||||
MAX_QUEUE_COUNT,
|
MAX_QUEUE_COUNT,
|
||||||
WATERMARK_QUEUE_SIZE,
|
WATERMARK_QUEUE_SIZE,
|
||||||
Self::dispatch_message,
|
Self::dispatch_message,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
<DidUpdate>::put(true);
|
DidUpdate::put(proceeded);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a parachain with given code.
|
fn on_initialize() {
|
||||||
/// Fails if given ID is already used.
|
<Self as Store>::DidUpdate::kill();
|
||||||
#[weight = SimpleDispatchInfo::FixedOperational(5_000_000)]
|
|
||||||
pub fn register_parachain(origin, id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
|
|
||||||
ensure_root(origin)?;
|
|
||||||
<Self as ParachainRegistrar<T::AccountId>>::register_parachain(id, code, initial_head_data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deregister a parachain with given id
|
fn on_finalize() {
|
||||||
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
assert!(<Self as Store>::DidUpdate::exists(), "Parachain heads must be updated once in the block");
|
||||||
pub fn deregister_parachain(origin, id: ParaId) -> Result {
|
|
||||||
ensure_root(origin)?;
|
|
||||||
<Self as ParachainRegistrar<T::AccountId>>::deregister_parachain(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_finalize(_n: T::BlockNumber) {
|
|
||||||
assert!(<Self as Store>::DidUpdate::take(), "Parachain heads must be updated once in the block");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,6 +279,42 @@ fn localized_payload(statement: Statement, parent_hash: ::primitives::Hash) -> V
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Trait> Module<T> {
|
impl<T: Trait> Module<T> {
|
||||||
|
/// Initialize the state of a new parachain/parathread.
|
||||||
|
pub fn initialize_para(
|
||||||
|
id: ParaId,
|
||||||
|
code: Vec<u8>,
|
||||||
|
initial_head_data: Vec<u8>,
|
||||||
|
) {
|
||||||
|
<Code>::insert(id, code);
|
||||||
|
<Heads>::insert(id, initial_head_data);
|
||||||
|
|
||||||
|
// Because there are no ordering guarantees that inherents
|
||||||
|
// are applied before regular transactions, a parachain candidate could
|
||||||
|
// be registered before the `UpdateHeads` inherent is processed. If so, messages
|
||||||
|
// could be sent to a parachain in the block it is registered.
|
||||||
|
<Watermarks<T>>::insert(id, <system::Module<T>>::block_number().saturating_sub(One::one()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup_para(
|
||||||
|
id: ParaId,
|
||||||
|
) {
|
||||||
|
<Code>::remove(id);
|
||||||
|
<Heads>::remove(id);
|
||||||
|
|
||||||
|
let watermark = <Watermarks<T>>::take(id);
|
||||||
|
|
||||||
|
// clear all routing entries _to_. But not those _from_.
|
||||||
|
if let Some(watermark) = watermark {
|
||||||
|
let now = <system::Module<T>>::block_number();
|
||||||
|
|
||||||
|
// iterate over all blocks between watermark and now + 1 (since messages might
|
||||||
|
// have already been sent to `id` in this block.
|
||||||
|
for unrouted_block in number_range(watermark, now).map(|n| n.saturating_add(One::one())) {
|
||||||
|
<UnroutedIngress<T>>::remove(&(unrouted_block, id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Dispatch some messages from a parachain.
|
/// Dispatch some messages from a parachain.
|
||||||
fn dispatch_message(
|
fn dispatch_message(
|
||||||
id: ParaId,
|
id: ParaId,
|
||||||
@@ -381,6 +327,8 @@ impl<T: Trait> Module<T> {
|
|||||||
system::RawOrigin::Signed(id.into_account()).into(),
|
system::RawOrigin::Signed(id.into_account()).into(),
|
||||||
ParachainDispatchOrigin::Parachain =>
|
ParachainDispatchOrigin::Parachain =>
|
||||||
Origin::Parachain(id).into(),
|
Origin::Parachain(id).into(),
|
||||||
|
ParachainDispatchOrigin::Root =>
|
||||||
|
system::RawOrigin::Root.into(),
|
||||||
};
|
};
|
||||||
let _ok = message_call.dispatch(origin).is_ok();
|
let _ok = message_call.dispatch(origin).is_ok();
|
||||||
// Not much to do with the result as it is. It's up to the parachain to ensure that the
|
// Not much to do with the result as it is. It's up to the parachain to ensure that the
|
||||||
@@ -415,6 +363,11 @@ impl<T: Trait> Module<T> {
|
|||||||
),
|
),
|
||||||
"Messages added when queue full"
|
"Messages added when queue full"
|
||||||
);
|
);
|
||||||
|
if !id.is_system() {
|
||||||
|
for m in upward_messages.iter() {
|
||||||
|
ensure!(m.origin != ParachainDispatchOrigin::Root, "bad message origin");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -431,6 +384,10 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
let mut ingress_update = BTreeMap::new();
|
let mut ingress_update = BTreeMap::new();
|
||||||
|
|
||||||
|
// we sort them in order to provide a fast lookup to ensure we can avoid duplicates in the
|
||||||
|
// needs_dispatch queue.
|
||||||
|
let mut ordered_needs_dispatch = NeedsDispatch::get();
|
||||||
|
|
||||||
for head in heads.iter() {
|
for head in heads.iter() {
|
||||||
let id = head.parachain_index();
|
let id = head.parachain_index();
|
||||||
<Heads>::insert(id, &head.candidate.head_data.0);
|
<Heads>::insert(id, &head.candidate.head_data.0);
|
||||||
@@ -452,9 +409,15 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Queue up upwards messages (from parachains to relay chain).
|
// Queue up upwards messages (from parachains to relay chain).
|
||||||
Self::queue_upward_messages(id, &head.candidate.upward_messages);
|
Self::queue_upward_messages(
|
||||||
|
id,
|
||||||
|
&head.candidate.upward_messages,
|
||||||
|
&mut ordered_needs_dispatch,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NeedsDispatch::put(ordered_needs_dispatch);
|
||||||
|
|
||||||
// apply the ingress update.
|
// apply the ingress update.
|
||||||
for (to, ingress_roots) in ingress_update {
|
for (to, ingress_roots) in ingress_update {
|
||||||
<UnroutedIngress<T>>::insert((now, to), ingress_roots);
|
<UnroutedIngress<T>>::insert((now, to), ingress_roots);
|
||||||
@@ -462,36 +425,46 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Place any new upward messages into our queue for later dispatch.
|
/// Place any new upward messages into our queue for later dispatch.
|
||||||
fn queue_upward_messages(id: ParaId, upward_messages: &[UpwardMessage]) {
|
///
|
||||||
|
/// `ordered_needs_dispatch` is mutated to ensure it reflects the new value of
|
||||||
|
/// `RelayDispatchQueueSize`. It is up to the caller to guarantee that it gets written into
|
||||||
|
/// storage after this call.
|
||||||
|
fn queue_upward_messages(
|
||||||
|
id: ParaId,
|
||||||
|
upward_messages: &[UpwardMessage],
|
||||||
|
ordered_needs_dispatch: &mut Vec<ParaId>,
|
||||||
|
) {
|
||||||
if !upward_messages.is_empty() {
|
if !upward_messages.is_empty() {
|
||||||
<RelayDispatchQueueSize>::mutate(id, |&mut(ref mut count, ref mut len)| {
|
RelayDispatchQueueSize::mutate(id, |&mut(ref mut count, ref mut len)| {
|
||||||
*count += upward_messages.len() as u32;
|
*count += upward_messages.len() as u32;
|
||||||
*len += upward_messages.iter()
|
*len += upward_messages.iter()
|
||||||
.fold(0, |a, x| a + x.data.len()) as u32;
|
.fold(0, |a, x| a + x.data.len()) as u32;
|
||||||
});
|
});
|
||||||
// Should never be able to fail assuming our state is uncorrupted, but best not
|
// Should never be able to fail assuming our state is uncorrupted, but best not
|
||||||
// to panic, even if it does.
|
// to panic, even if it does.
|
||||||
let _ = <RelayDispatchQueue>::append(id, upward_messages);
|
let _ = RelayDispatchQueue::append(id, upward_messages);
|
||||||
|
if let Err(i) = ordered_needs_dispatch.binary_search(&id) {
|
||||||
|
// same.
|
||||||
|
ordered_needs_dispatch.insert(i, id);
|
||||||
|
} else {
|
||||||
|
sr_primitives::print("ordered_needs_dispatch contains id?!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple round-robin dispatcher, using block number modulo parachain count
|
/// Simple FIFO dispatcher.
|
||||||
/// to decide which takes precedence and proceeding from there.
|
|
||||||
fn dispatch_upward_messages(
|
fn dispatch_upward_messages(
|
||||||
now: T::BlockNumber,
|
|
||||||
active_parachains: &[ParaId],
|
|
||||||
max_queue_count: usize,
|
max_queue_count: usize,
|
||||||
watermark_queue_size: usize,
|
watermark_queue_size: usize,
|
||||||
mut dispatch_message: impl FnMut(ParaId, ParachainDispatchOrigin, &[u8]),
|
mut dispatch_message: impl FnMut(ParaId, ParachainDispatchOrigin, &[u8]),
|
||||||
) {
|
) {
|
||||||
let para_count = active_parachains.len();
|
let queueds = NeedsDispatch::get();
|
||||||
let offset = (now % T::BlockNumber::from(para_count as u32))
|
let mut drained_count = 0usize;
|
||||||
.checked_into::<usize>()
|
|
||||||
.expect("value is modulo a usize value; qed");
|
|
||||||
|
|
||||||
let mut dispatched_count = 0usize;
|
let mut dispatched_count = 0usize;
|
||||||
let mut dispatched_size = 0usize;
|
let mut dispatched_size = 0usize;
|
||||||
for id in active_parachains.iter().cycle().skip(offset).take(para_count) {
|
for id in queueds.iter() {
|
||||||
|
drained_count += 1;
|
||||||
|
|
||||||
let (count, size) = <RelayDispatchQueueSize>::get(id);
|
let (count, size) = <RelayDispatchQueueSize>::get(id);
|
||||||
let count = count as usize;
|
let count = count as usize;
|
||||||
let size = size as usize;
|
let size = size as usize;
|
||||||
@@ -501,8 +474,8 @@ impl<T: Trait> Module<T> {
|
|||||||
) {
|
) {
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
// still dispatching messages...
|
// still dispatching messages...
|
||||||
<RelayDispatchQueueSize>::remove(id);
|
RelayDispatchQueueSize::remove(id);
|
||||||
let messages = <RelayDispatchQueue>::take(id);
|
let messages = RelayDispatchQueue::take(id);
|
||||||
for UpwardMessage { origin, data } in messages.into_iter() {
|
for UpwardMessage { origin, data } in messages.into_iter() {
|
||||||
dispatch_message(*id, origin, &data);
|
dispatch_message(*id, origin, &data);
|
||||||
}
|
}
|
||||||
@@ -516,6 +489,7 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NeedsDispatch::put(&queueds[drained_count..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the current block's duty roster using system's random seed.
|
/// Calculate the current block's duty roster using system's random seed.
|
||||||
@@ -523,19 +497,24 @@ impl<T: Trait> Module<T> {
|
|||||||
pub fn calculate_duty_roster() -> (DutyRoster, [u8; 32]) {
|
pub fn calculate_duty_roster() -> (DutyRoster, [u8; 32]) {
|
||||||
let parachains = Self::active_parachains();
|
let parachains = Self::active_parachains();
|
||||||
let parachain_count = parachains.len();
|
let parachain_count = parachains.len();
|
||||||
|
|
||||||
// TODO: use decode length. substrate #2794
|
// TODO: use decode length. substrate #2794
|
||||||
let validator_count = Self::authorities().len();
|
let validator_count = Self::authorities().len();
|
||||||
let validators_per_parachain = if parachain_count != 0 { (validator_count - 1) / parachain_count } else { 0 };
|
let validators_per_parachain =
|
||||||
|
if parachain_count == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(validator_count - 1) / parachain_count
|
||||||
|
};
|
||||||
|
|
||||||
let mut roles_val = (0..validator_count).map(|i| match i {
|
let mut roles_val = (0..validator_count).map(|i| match i {
|
||||||
i if i < parachain_count * validators_per_parachain => {
|
i if i < parachain_count * validators_per_parachain => {
|
||||||
let idx = i / validators_per_parachain;
|
let idx = i / validators_per_parachain;
|
||||||
Chain::Parachain(parachains[idx].clone())
|
Chain::Parachain(parachains[idx].0.clone())
|
||||||
}
|
}
|
||||||
_ => Chain::Relay,
|
_ => Chain::Relay,
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
||||||
let mut seed = {
|
let mut seed = {
|
||||||
let phrase = b"validator_role_pairs";
|
let phrase = b"validator_role_pairs";
|
||||||
let seed = randomness_collective_flip::Module::<T>::random(&phrase[..]);
|
let seed = randomness_collective_flip::Module::<T>::random(&phrase[..]);
|
||||||
@@ -621,9 +600,17 @@ impl<T: Trait> Module<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_egress_queue_roots(head: &AttestedCandidate, active_parachains: &[ParaId]) -> Result {
|
/// Get the currently active set of parachains.
|
||||||
|
pub fn active_parachains() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> {
|
||||||
|
T::ActiveParachains::active_paras()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_egress_queue_roots(
|
||||||
|
head: &AttestedCandidate,
|
||||||
|
active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
|
||||||
|
) -> Result {
|
||||||
let mut last_egress_id = None;
|
let mut last_egress_id = None;
|
||||||
let mut iter = active_parachains.iter();
|
let mut iter = active_parachains.iter().map(|x| x.0);
|
||||||
for (egress_para_id, root) in &head.candidate.egress_queue_roots {
|
for (egress_para_id, root) in &head.candidate.egress_queue_roots {
|
||||||
// egress routes should be ascending order by parachain ID without duplicate.
|
// egress routes should be ascending order by parachain ID without duplicate.
|
||||||
ensure!(
|
ensure!(
|
||||||
@@ -645,7 +632,7 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
// can't route to a parachain which doesn't exist
|
// can't route to a parachain which doesn't exist
|
||||||
ensure!(
|
ensure!(
|
||||||
iter.find(|x| x == &egress_para_id).is_some(),
|
iter.find(|x| x == egress_para_id).is_some(),
|
||||||
"Routing to non-existent parachain"
|
"Routing to non-existent parachain"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -656,8 +643,10 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
// check the attestations on these candidates. The candidates should have been checked
|
// check the attestations on these candidates. The candidates should have been checked
|
||||||
// that each candidates' chain ID is valid.
|
// that each candidates' chain ID is valid.
|
||||||
fn check_candidates(attested_candidates: &[AttestedCandidate], active_parachains: &[ParaId])
|
fn check_candidates(
|
||||||
-> rstd::result::Result<IncludedBlocks<T>, &'static str>
|
attested_candidates: &[AttestedCandidate],
|
||||||
|
active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
|
||||||
|
) -> rstd::result::Result<IncludedBlocks<T>, &'static str>
|
||||||
{
|
{
|
||||||
use primitives::parachain::ValidityAttestation;
|
use primitives::parachain::ValidityAttestation;
|
||||||
use sr_primitives::traits::AppVerify;
|
use sr_primitives::traits::AppVerify;
|
||||||
@@ -815,7 +804,7 @@ impl<T: Trait> Module<T> {
|
|||||||
actual_number: <system::Module<T>>::block_number(),
|
actual_number: <system::Module<T>>::block_number(),
|
||||||
session: <session::Module<T>>::current_index(),
|
session: <session::Module<T>>::current_index(),
|
||||||
random_seed,
|
random_seed,
|
||||||
active_parachains: active_parachains.to_vec(),
|
active_parachains: active_parachains.iter().map(|x| x.0).collect(),
|
||||||
para_blocks: para_block_hashes,
|
para_blocks: para_block_hashes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -877,6 +866,17 @@ impl<T: Trait> ProvideInherent for Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure that the origin `o` represents a parachain.
|
||||||
|
/// Returns `Ok` with the parachain ID that effected the extrinsic or an `Err` otherwise.
|
||||||
|
pub fn ensure_parachain<OuterOrigin>(o: OuterOrigin) -> result::Result<ParaId, &'static str>
|
||||||
|
where OuterOrigin: Into<result::Result<Origin, OuterOrigin>>
|
||||||
|
{
|
||||||
|
match o.into() {
|
||||||
|
Ok(Origin::Parachain(id)) => Ok(id),
|
||||||
|
_ => Err("bad origin: expected to be a parachain origin"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -887,12 +887,12 @@ mod tests {
|
|||||||
use substrate_trie::NodeCodec;
|
use substrate_trie::NodeCodec;
|
||||||
use sr_primitives::{
|
use sr_primitives::{
|
||||||
Perbill,
|
Perbill,
|
||||||
traits::{BlakeTwo256, IdentityLookup, ConvertInto, OnInitialize},
|
traits::{BlakeTwo256, IdentityLookup, ConvertInto, OnInitialize, OnFinalize},
|
||||||
testing::{UintAuthorityId, Header},
|
testing::{UintAuthorityId, Header},
|
||||||
curve::PiecewiseLinear,
|
curve::PiecewiseLinear,
|
||||||
};
|
};
|
||||||
use primitives::{
|
use primitives::{
|
||||||
parachain::{CandidateReceipt, HeadData, ValidityAttestation, ValidatorId},
|
parachain::{CandidateReceipt, HeadData, ValidityAttestation, ValidatorId, Info as ParaInfo, Scheduling},
|
||||||
BlockNumber,
|
BlockNumber,
|
||||||
};
|
};
|
||||||
use crate::constants::time::*;
|
use crate::constants::time::*;
|
||||||
@@ -901,6 +901,8 @@ mod tests {
|
|||||||
impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
|
impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
|
||||||
};
|
};
|
||||||
use crate::parachains;
|
use crate::parachains;
|
||||||
|
use crate::registrar;
|
||||||
|
use crate::slots;
|
||||||
|
|
||||||
impl_outer_origin! {
|
impl_outer_origin! {
|
||||||
pub enum Origin for Test {
|
pub enum Origin for Test {
|
||||||
@@ -1048,15 +1050,47 @@ mod tests {
|
|||||||
type RewardAttestation = ();
|
type RewardAttestation = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types!{
|
||||||
|
pub const LeasePeriod: u64 = 10;
|
||||||
|
pub const EndingPeriod: u64 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl slots::Trait for Test {
|
||||||
|
type Event = ();
|
||||||
|
type Currency = balances::Module<Test>;
|
||||||
|
type Parachains = registrar::Module<Test>;
|
||||||
|
type EndingPeriod = EndingPeriod;
|
||||||
|
type LeasePeriod = LeasePeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub const ParathreadDeposit: Balance = 10;
|
||||||
|
pub const QueueSize: usize = 2;
|
||||||
|
pub const MaxRetries: u32 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl registrar::Trait for Test {
|
||||||
|
type Event = ();
|
||||||
|
type Origin = Origin;
|
||||||
|
type Currency = balances::Module<Test>;
|
||||||
|
type ParathreadDeposit = ParathreadDeposit;
|
||||||
|
type SwapAux = slots::Module<Test>;
|
||||||
|
type QueueSize = QueueSize;
|
||||||
|
type MaxRetries = MaxRetries;
|
||||||
|
}
|
||||||
|
|
||||||
impl Trait for Test {
|
impl Trait for Test {
|
||||||
type Origin = Origin;
|
type Origin = Origin;
|
||||||
type Call = Call;
|
type Call = Call;
|
||||||
type ParachainCurrency = balances::Module<Test>;
|
type ParachainCurrency = balances::Module<Test>;
|
||||||
|
type ActiveParachains = registrar::Module<Test>;
|
||||||
|
type Registrar = registrar::Module<Test>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Parachains = Module<Test>;
|
type Parachains = Module<Test>;
|
||||||
type System = system::Module<Test>;
|
type System = system::Module<Test>;
|
||||||
type RandomnessCollectiveFlip = randomness_collective_flip::Module<Test>;
|
type RandomnessCollectiveFlip = randomness_collective_flip::Module<Test>;
|
||||||
|
type Registrar = registrar::Module<Test>;
|
||||||
|
|
||||||
fn new_test_ext(parachains: Vec<(ParaId, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
|
fn new_test_ext(parachains: Vec<(ParaId, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
|
||||||
use staking::StakerStatus;
|
use staking::StakerStatus;
|
||||||
@@ -1096,9 +1130,12 @@ mod tests {
|
|||||||
|
|
||||||
let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();
|
let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();
|
||||||
|
|
||||||
GenesisConfig::<Test> {
|
GenesisConfig {
|
||||||
parachains,
|
|
||||||
authorities: authorities.clone(),
|
authorities: authorities.clone(),
|
||||||
|
}.assimilate_storage(&mut t).unwrap();
|
||||||
|
|
||||||
|
registrar::GenesisConfig::<Test> {
|
||||||
|
parachains,
|
||||||
_phdata: Default::default(),
|
_phdata: Default::default(),
|
||||||
}.assimilate_storage(&mut t).unwrap();
|
}.assimilate_storage(&mut t).unwrap();
|
||||||
|
|
||||||
@@ -1217,6 +1254,32 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_block() {
|
||||||
|
println!("Initializing {}", System::block_number());
|
||||||
|
System::on_initialize(System::block_number());
|
||||||
|
Registrar::on_initialize(System::block_number());
|
||||||
|
Parachains::on_initialize(System::block_number());
|
||||||
|
}
|
||||||
|
fn run_to_block(n: u64) {
|
||||||
|
println!("Running until block {}", n);
|
||||||
|
while System::block_number() < n {
|
||||||
|
if System::block_number() > 1 {
|
||||||
|
println!("Finalizing {}", System::block_number());
|
||||||
|
Parachains::on_finalize(System::block_number());
|
||||||
|
Registrar::on_finalize(System::block_number());
|
||||||
|
System::on_finalize(System::block_number());
|
||||||
|
}
|
||||||
|
System::set_block_number(System::block_number() + 1);
|
||||||
|
init_block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queue_upward_messages(id: ParaId, upward_messages: &[UpwardMessage]) {
|
||||||
|
NeedsDispatch::mutate(|nd|
|
||||||
|
Parachains::queue_upward_messages(id, upward_messages, nd)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_dispatch_upward_works() {
|
fn check_dispatch_upward_works() {
|
||||||
let parachains = vec![
|
let parachains = vec![
|
||||||
@@ -1225,16 +1288,16 @@ mod tests {
|
|||||||
(2u32.into(), vec![], vec![]),
|
(2u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
||||||
let parachains = vec![0.into(), 1.into(), 2.into()];
|
init_block();
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 4] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 4] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(1.into(), &vec![
|
queue_upward_messages(1.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 4] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 4] }
|
||||||
]);
|
]);
|
||||||
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
||||||
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
||||||
Parachains::dispatch_upward_messages(0, ¶chains, 2, 3, dummy);
|
Parachains::dispatch_upward_messages(2, 3, dummy);
|
||||||
assert_eq!(dispatched, vec![
|
assert_eq!(dispatched, vec![
|
||||||
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 4])
|
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 4])
|
||||||
]);
|
]);
|
||||||
@@ -1242,19 +1305,19 @@ mod tests {
|
|||||||
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
|
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
|
||||||
});
|
});
|
||||||
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
||||||
let parachains = vec![0.into(), 1.into(), 2.into()];
|
init_block();
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(1.into(), &vec![
|
queue_upward_messages(1.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(2.into(), &vec![
|
queue_upward_messages(2.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
|
||||||
]);
|
]);
|
||||||
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
||||||
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
||||||
Parachains::dispatch_upward_messages(0, ¶chains, 2, 3, dummy);
|
Parachains::dispatch_upward_messages(2, 3, dummy);
|
||||||
assert_eq!(dispatched, vec![
|
assert_eq!(dispatched, vec![
|
||||||
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
|
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
|
||||||
(2.into(), ParachainDispatchOrigin::Parachain, vec![2])
|
(2.into(), ParachainDispatchOrigin::Parachain, vec![2])
|
||||||
@@ -1264,44 +1327,44 @@ mod tests {
|
|||||||
assert!(<RelayDispatchQueue>::get(ParaId::from(2)).is_empty());
|
assert!(<RelayDispatchQueue>::get(ParaId::from(2)).is_empty());
|
||||||
});
|
});
|
||||||
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
||||||
let parachains = vec![0.into(), 1.into(), 2.into()];
|
init_block();
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(1.into(), &vec![
|
queue_upward_messages(1.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(2.into(), &vec![
|
queue_upward_messages(2.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
|
||||||
]);
|
]);
|
||||||
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
||||||
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
||||||
Parachains::dispatch_upward_messages(1, ¶chains, 2, 3, dummy);
|
Parachains::dispatch_upward_messages(2, 3, dummy);
|
||||||
assert_eq!(dispatched, vec![
|
assert_eq!(dispatched, vec![
|
||||||
(1.into(), ParachainDispatchOrigin::Parachain, vec![1; 2]),
|
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
|
||||||
(2.into(), ParachainDispatchOrigin::Parachain, vec![2])
|
(2.into(), ParachainDispatchOrigin::Parachain, vec![2])
|
||||||
]);
|
]);
|
||||||
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(0)).len(), 1);
|
assert!(<RelayDispatchQueue>::get(ParaId::from(0)).is_empty());
|
||||||
assert!(<RelayDispatchQueue>::get(ParaId::from(1)).is_empty());
|
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
|
||||||
assert!(<RelayDispatchQueue>::get(ParaId::from(2)).is_empty());
|
assert!(<RelayDispatchQueue>::get(ParaId::from(2)).is_empty());
|
||||||
});
|
});
|
||||||
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
with_externalities(&mut new_test_ext(parachains.clone()), || {
|
||||||
let parachains = vec![0.into(), 1.into(), 2.into()];
|
init_block();
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(1.into(), &vec![
|
queue_upward_messages(1.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
|
||||||
]);
|
]);
|
||||||
Parachains::queue_upward_messages(2.into(), &vec![
|
queue_upward_messages(2.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
|
||||||
]);
|
]);
|
||||||
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
|
||||||
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
|
||||||
Parachains::dispatch_upward_messages(2, ¶chains, 2, 3, dummy);
|
Parachains::dispatch_upward_messages(2, 3, dummy);
|
||||||
assert_eq!(dispatched, vec![
|
assert_eq!(dispatched, vec![
|
||||||
|
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
|
||||||
(2.into(), ParachainDispatchOrigin::Parachain, vec![2]),
|
(2.into(), ParachainDispatchOrigin::Parachain, vec![2]),
|
||||||
(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2])
|
|
||||||
]);
|
]);
|
||||||
assert!(<RelayDispatchQueue>::get(ParaId::from(0)).is_empty());
|
assert!(<RelayDispatchQueue>::get(ParaId::from(0)).is_empty());
|
||||||
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
|
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
|
||||||
@@ -1315,20 +1378,21 @@ mod tests {
|
|||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] }
|
||||||
];
|
];
|
||||||
assert_ok!(Parachains::check_upward_messages(0.into(), &messages, 2, 3));
|
assert_ok!(Parachains::check_upward_messages(0.into(), &messages, 2, 3));
|
||||||
|
|
||||||
// all good.
|
// all good.
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
||||||
]);
|
]);
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1, 2] }
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1, 2] }
|
||||||
];
|
];
|
||||||
assert_ok!(Parachains::check_upward_messages(0.into(), &messages, 2, 3));
|
assert_ok!(Parachains::check_upward_messages(0.into(), &messages, 2, 3));
|
||||||
Parachains::queue_upward_messages(0.into(), &messages);
|
queue_upward_messages(0.into(), &messages);
|
||||||
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(0)), vec![
|
assert_eq!(<RelayDispatchQueue>::get(ParaId::from(0)), vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1, 2] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1, 2] },
|
||||||
@@ -1342,6 +1406,7 @@ mod tests {
|
|||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// oversize, but ok since it's just one and the queue is empty.
|
// oversize, but ok since it's just one and the queue is empty.
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0; 4] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0; 4] },
|
||||||
@@ -1377,8 +1442,9 @@ mod tests {
|
|||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// too many messages.
|
// too many messages.
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
||||||
]);
|
]);
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
@@ -1398,8 +1464,9 @@ mod tests {
|
|||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// too much data.
|
// too much data.
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0, 1] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0, 1] },
|
||||||
]);
|
]);
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
@@ -1418,8 +1485,9 @@ mod tests {
|
|||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// bad - already an oversize messages queued.
|
// bad - already an oversize messages queued.
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0; 4] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0; 4] },
|
||||||
]);
|
]);
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
@@ -1438,8 +1506,9 @@ mod tests {
|
|||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
];
|
];
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// bad - oversized and already a message queued.
|
// bad - oversized and already a message queued.
|
||||||
Parachains::queue_upward_messages(0.into(), &vec![
|
queue_upward_messages(0.into(), &vec![
|
||||||
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
|
||||||
]);
|
]);
|
||||||
let messages = vec![
|
let messages = vec![
|
||||||
@@ -1461,6 +1530,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// parachain 0 is self
|
// parachain 0 is self
|
||||||
let mut candidates = vec![
|
let mut candidates = vec![
|
||||||
new_candidate_with_upward_messages(0, vec![
|
new_candidate_with_upward_messages(0, vec![
|
||||||
@@ -1490,9 +1560,10 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 100u32.into()]);
|
run_to_block(2);
|
||||||
assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1,2,3]));
|
assert_eq!(Parachains::active_parachains(), vec![(5u32.into(), None), (100u32.into(), None)]);
|
||||||
assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4,5,6]));
|
assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1, 2, 3]));
|
||||||
|
assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4, 5, 6]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1504,20 +1575,28 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 100u32.into()]);
|
run_to_block(2);
|
||||||
|
assert_eq!(Parachains::active_parachains(), vec![(5u32.into(), None), (100u32.into(), None)]);
|
||||||
|
|
||||||
assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1,2,3]));
|
assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1,2,3]));
|
||||||
assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4,5,6]));
|
assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4,5,6]));
|
||||||
|
|
||||||
assert_ok!(Parachains::register_parachain(Origin::ROOT, 99u32.into(), vec![7,8,9], vec![1, 1, 1]));
|
assert_ok!(Registrar::register_para(Origin::ROOT, 99u32.into(), ParaInfo{scheduling: Scheduling::Always}, vec![7,8,9], vec![1, 1, 1]));
|
||||||
|
assert_ok!(Parachains::set_heads(Origin::NONE, vec![]));
|
||||||
|
|
||||||
assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 99u32.into(), 100u32.into()]);
|
run_to_block(3);
|
||||||
assert_eq!(Parachains::parachain_code(ParaId::from(99u32)), Some(vec![7,8,9]));
|
|
||||||
|
|
||||||
assert_ok!(Parachains::deregister_parachain(Origin::ROOT, 5u32.into()));
|
assert_eq!(Parachains::active_parachains(), vec![(5u32.into(), None), (99u32.into(), None), (100u32.into(), None)]);
|
||||||
|
assert_eq!(Parachains::parachain_code(&ParaId::from(99u32)), Some(vec![7,8,9]));
|
||||||
|
|
||||||
assert_eq!(Parachains::active_parachains(), vec![99u32.into(), 100u32.into()]);
|
assert_ok!(Registrar::deregister_para(Origin::ROOT, 5u32.into()));
|
||||||
assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), None);
|
assert_ok!(Parachains::set_heads(Origin::NONE, vec![]));
|
||||||
|
|
||||||
|
// parachain still active this block. another block must pass before it's inactive.
|
||||||
|
run_to_block(4);
|
||||||
|
|
||||||
|
assert_eq!(Parachains::active_parachains(), vec![(99u32.into(), None), (100u32.into(), None)]);
|
||||||
|
assert_eq!(Parachains::parachain_code(&ParaId::from(5u32)), None);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1529,6 +1608,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
let check_roster = |duty_roster: &DutyRoster| {
|
let check_roster = |duty_roster: &DutyRoster| {
|
||||||
assert_eq!(duty_roster.validator_duty.len(), 8);
|
assert_eq!(duty_roster.validator_duty.len(), 8);
|
||||||
for i in (0..2).map(ParaId::from) {
|
for i in (0..2).map(ParaId::from) {
|
||||||
@@ -1564,6 +1644,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
let candidate = AttestedCandidate {
|
let candidate = AttestedCandidate {
|
||||||
validity_votes: vec![],
|
validity_votes: vec![],
|
||||||
validator_indices: BitVec::new(),
|
validator_indices: BitVec::new(),
|
||||||
@@ -1592,6 +1673,9 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
|
assert_eq!(Parachains::active_parachains().len(), 2);
|
||||||
|
|
||||||
let mut candidate_a = AttestedCandidate {
|
let mut candidate_a = AttestedCandidate {
|
||||||
validity_votes: vec![],
|
validity_votes: vec![],
|
||||||
validator_indices: BitVec::new(),
|
validator_indices: BitVec::new(),
|
||||||
@@ -1645,6 +1729,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
let mut candidate = AttestedCandidate {
|
let mut candidate = AttestedCandidate {
|
||||||
validity_votes: vec![],
|
validity_votes: vec![],
|
||||||
validator_indices: BitVec::new(),
|
validator_indices: BitVec::new(),
|
||||||
@@ -1681,6 +1766,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
let mut candidate = AttestedCandidate {
|
let mut candidate = AttestedCandidate {
|
||||||
validity_votes: vec![],
|
validity_votes: vec![],
|
||||||
validator_indices: BitVec::new(),
|
validator_indices: BitVec::new(),
|
||||||
@@ -1711,8 +1797,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ingress_works() {
|
fn ingress_works() {
|
||||||
use sr_primitives::traits::OnFinalize;
|
|
||||||
|
|
||||||
let parachains = vec![
|
let parachains = vec![
|
||||||
(0u32.into(), vec![], vec![]),
|
(0u32.into(), vec![], vec![]),
|
||||||
(1u32.into(), vec![], vec![]),
|
(1u32.into(), vec![], vec![]),
|
||||||
@@ -1723,8 +1807,9 @@ mod tests {
|
|||||||
assert_eq!(Parachains::ingress(ParaId::from(1), None), Some(Vec::new()));
|
assert_eq!(Parachains::ingress(ParaId::from(1), None), Some(Vec::new()));
|
||||||
assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
|
assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
|
||||||
|
|
||||||
|
init_block();
|
||||||
for i in 1..10 {
|
for i in 1..10 {
|
||||||
System::set_block_number(i);
|
run_to_block(i);
|
||||||
|
|
||||||
let from_a = vec![(1.into(), [i as u8; 32].into())];
|
let from_a = vec![(1.into(), [i as u8; 32].into())];
|
||||||
let mut candidate_a = AttestedCandidate {
|
let mut candidate_a = AttestedCandidate {
|
||||||
@@ -1765,11 +1850,9 @@ mod tests {
|
|||||||
set_heads(vec![candidate_a, candidate_b]),
|
set_heads(vec![candidate_a, candidate_b]),
|
||||||
Origin::NONE,
|
Origin::NONE,
|
||||||
));
|
));
|
||||||
|
|
||||||
Parachains::on_finalize(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System::set_block_number(10);
|
run_to_block(10);
|
||||||
assert_ok!(Parachains::dispatch(
|
assert_ok!(Parachains::dispatch(
|
||||||
set_heads(vec![]),
|
set_heads(vec![]),
|
||||||
Origin::NONE,
|
Origin::NONE,
|
||||||
@@ -1795,7 +1878,7 @@ mod tests {
|
|||||||
))).collect::<Vec<_>>()),
|
))).collect::<Vec<_>>()),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_ok!(Parachains::deregister_parachain(Origin::ROOT, 1u32.into()));
|
assert_ok!(Registrar::deregister_para(Origin::ROOT, 1u32.into()));
|
||||||
|
|
||||||
// after deregistering, there is no ingress to 1, but unrouted messages
|
// after deregistering, there is no ingress to 1, but unrouted messages
|
||||||
// from 1 stick around.
|
// from 1 stick around.
|
||||||
@@ -1804,8 +1887,7 @@ mod tests {
|
|||||||
vec![(1.into(), [i as u8; 32].into())]
|
vec![(1.into(), [i as u8; 32].into())]
|
||||||
))).collect::<Vec<_>>()));
|
))).collect::<Vec<_>>()));
|
||||||
|
|
||||||
Parachains::on_finalize(10);
|
run_to_block(11);
|
||||||
System::set_block_number(11);
|
|
||||||
|
|
||||||
let mut candidate_c = AttestedCandidate {
|
let mut candidate_c = AttestedCandidate {
|
||||||
validity_votes: vec![],
|
validity_votes: vec![],
|
||||||
@@ -1828,8 +1910,7 @@ mod tests {
|
|||||||
Origin::NONE,
|
Origin::NONE,
|
||||||
));
|
));
|
||||||
|
|
||||||
Parachains::on_finalize(11);
|
run_to_block(12);
|
||||||
System::set_block_number(12);
|
|
||||||
|
|
||||||
// at the next block, ingress to 99 should be empty.
|
// at the next block, ingress to 99 should be empty.
|
||||||
assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
|
assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
|
||||||
@@ -1845,6 +1926,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// parachain 99 does not exist
|
// parachain 99 does not exist
|
||||||
let non_existent = vec![(99.into(), [1; 32].into())];
|
let non_existent = vec![(99.into(), [1; 32].into())];
|
||||||
let mut candidate = new_candidate_with_egress_roots(non_existent);
|
let mut candidate = new_candidate_with_egress_roots(non_existent);
|
||||||
@@ -1869,6 +1951,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// parachain 0 is self
|
// parachain 0 is self
|
||||||
let to_self = vec![(0.into(), [1; 32].into())];
|
let to_self = vec![(0.into(), [1; 32].into())];
|
||||||
let mut candidate = new_candidate_with_egress_roots(to_self);
|
let mut candidate = new_candidate_with_egress_roots(to_self);
|
||||||
@@ -1893,6 +1976,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// parachain 0 is self
|
// parachain 0 is self
|
||||||
let out_of_order = vec![(1.into(), [1; 32].into()), ((0.into(), [1; 32].into()))];
|
let out_of_order = vec![(1.into(), [1; 32].into()), ((0.into(), [1; 32].into()))];
|
||||||
let mut candidate = new_candidate_with_egress_roots(out_of_order);
|
let mut candidate = new_candidate_with_egress_roots(out_of_order);
|
||||||
@@ -1917,6 +2001,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
with_externalities(&mut new_test_ext(parachains), || {
|
with_externalities(&mut new_test_ext(parachains), || {
|
||||||
|
run_to_block(2);
|
||||||
// parachain 0 is self
|
// parachain 0 is self
|
||||||
let contains_empty_trie_root = vec![(1.into(), [1; 32].into()), ((2.into(), EMPTY_TRIE_ROOT.into()))];
|
let contains_empty_trie_root = vec![(1.into(), [1; 32].into()), ((2.into(), EMPTY_TRIE_ROOT.into()))];
|
||||||
let mut candidate = new_candidate_with_egress_roots(contains_empty_trie_root);
|
let mut candidate = new_candidate_with_egress_roots(contains_empty_trie_root);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -19,20 +19,21 @@
|
|||||||
//! information for commissioning and decommissioning them.
|
//! information for commissioning and decommissioning them.
|
||||||
|
|
||||||
use rstd::{prelude::*, mem::swap, convert::TryInto};
|
use rstd::{prelude::*, mem::swap, convert::TryInto};
|
||||||
use sr_primitives::traits::{CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash};
|
use sr_primitives::traits::{CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash, AccountIdConversion};
|
||||||
use sr_primitives::weights::SimpleDispatchInfo;
|
use sr_primitives::weights::SimpleDispatchInfo;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode, Codec};
|
||||||
use srml_support::{
|
use srml_support::{
|
||||||
decl_module, decl_storage, decl_event, ensure,
|
decl_module, decl_storage, decl_event, ensure,
|
||||||
traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get},
|
traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get},
|
||||||
};
|
};
|
||||||
use primitives::parachain::AccountIdConversion;
|
use primitives::parachain::{
|
||||||
use crate::parachains::ParachainRegistrar;
|
SwapAux, PARACHAIN_INFO, Id as ParaId
|
||||||
|
};
|
||||||
use system::{ensure_signed, ensure_root};
|
use system::{ensure_signed, ensure_root};
|
||||||
|
use crate::registrar::{Registrar, swap_ordered_existence};
|
||||||
use crate::slot_range::{SlotRange, SLOT_RANGE_COUNT};
|
use crate::slot_range::{SlotRange, SLOT_RANGE_COUNT};
|
||||||
|
|
||||||
type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
|
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.
|
/// The module's configuration trait.
|
||||||
pub trait Trait: system::Trait {
|
pub trait Trait: system::Trait {
|
||||||
@@ -43,7 +44,7 @@ pub trait Trait: system::Trait {
|
|||||||
type Currency: ReservableCurrency<Self::AccountId>;
|
type Currency: ReservableCurrency<Self::AccountId>;
|
||||||
|
|
||||||
/// The parachain registrar type.
|
/// The parachain registrar type.
|
||||||
type Parachains: ParachainRegistrar<Self::AccountId>;
|
type Parachains: Registrar<Self::AccountId>;
|
||||||
|
|
||||||
/// The number of blocks over which an auction may be retroactively ended.
|
/// The number of blocks over which an auction may be retroactively ended.
|
||||||
type EndingPeriod: Get<Self::BlockNumber>;
|
type EndingPeriod: Get<Self::BlockNumber>;
|
||||||
@@ -74,7 +75,7 @@ pub struct NewBidder<AccountId> {
|
|||||||
/// The desired target of a bidder in an auction.
|
/// The desired target of a bidder in an auction.
|
||||||
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
|
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
pub enum Bidder<AccountId, ParaId> {
|
pub enum Bidder<AccountId> {
|
||||||
/// An account ID, funds coming from that account.
|
/// An account ID, funds coming from that account.
|
||||||
New(NewBidder<AccountId>),
|
New(NewBidder<AccountId>),
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ pub enum Bidder<AccountId, ParaId> {
|
|||||||
Existing(ParaId),
|
Existing(ParaId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AccountId: Clone, ParaId: AccountIdConversion<AccountId>> Bidder<AccountId, ParaId> {
|
impl<AccountId: Clone + Default + Codec> Bidder<AccountId> {
|
||||||
/// Get the account that will fund this bid.
|
/// Get the account that will fund this bid.
|
||||||
fn funding_account(&self) -> AccountId {
|
fn funding_account(&self) -> AccountId {
|
||||||
match self {
|
match self {
|
||||||
@@ -110,10 +111,12 @@ pub enum IncomingParachain<AccountId, Hash> {
|
|||||||
|
|
||||||
type LeasePeriodOf<T> = <T as system::Trait>::BlockNumber;
|
type LeasePeriodOf<T> = <T as system::Trait>::BlockNumber;
|
||||||
// Winning data type. This encodes the top bidders of each range together with their bid.
|
// 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];
|
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
|
// 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.
|
// 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)>;
|
type WinnersData<T> =
|
||||||
|
Vec<(Option<NewBidder<<T as system::Trait>::AccountId>>, ParaId, BalanceOf<T>, SlotRange)>;
|
||||||
|
|
||||||
// This module's storage items.
|
// This module's storage items.
|
||||||
decl_storage! {
|
decl_storage! {
|
||||||
@@ -122,9 +125,9 @@ decl_storage! {
|
|||||||
/// The number of auctions that been started so far.
|
/// The number of auctions that been started so far.
|
||||||
pub AuctionCounter get(auction_counter): AuctionIndex;
|
pub AuctionCounter get(auction_counter): AuctionIndex;
|
||||||
|
|
||||||
/// All `ParaId` values that are managed by this module. This includes chains that are not
|
/// Ordered list of all `ParaId` values that are managed by this module. This includes
|
||||||
/// yet deployed (but have won an auction in the future).
|
/// chains that are not yet deployed (but have won an auction in the future).
|
||||||
pub ManagedIds get(managed_ids): Vec<ParaIdOf<T>>;
|
pub ManagedIds get(managed_ids): Vec<ParaId>;
|
||||||
|
|
||||||
/// Various amounts on deposit for each parachain. An entry in `ManagedIds` implies a non-
|
/// Various amounts on deposit for each parachain. An entry in `ManagedIds` implies a non-
|
||||||
/// default entry here.
|
/// default entry here.
|
||||||
@@ -139,7 +142,7 @@ decl_storage! {
|
|||||||
/// If a parachain doesn't exist *yet* but is scheduled to exist in the future, then it
|
/// 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
|
/// 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.
|
/// 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>>;
|
pub Deposits get(deposits): map ParaId => Vec<BalanceOf<T>>;
|
||||||
|
|
||||||
/// Information relating to the current auction, if there is one.
|
/// Information relating to the current auction, if there is one.
|
||||||
///
|
///
|
||||||
@@ -155,22 +158,37 @@ decl_storage! {
|
|||||||
|
|
||||||
/// Amounts currently reserved in the accounts of the bidders currently winning
|
/// Amounts currently reserved in the accounts of the bidders currently winning
|
||||||
/// (sub-)ranges.
|
/// (sub-)ranges.
|
||||||
pub ReservedAmounts get(reserved_amounts): map Bidder<T::AccountId, ParaIdOf<T>> => Option<BalanceOf<T>>;
|
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.
|
/// 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.
|
/// This is cleared out on the first block of the lease period.
|
||||||
pub OnboardQueue get(onboard_queue): map LeasePeriodOf<T> => Vec<ParaIdOf<T>>;
|
pub OnboardQueue get(onboard_queue): map LeasePeriodOf<T> => Vec<ParaId>;
|
||||||
|
|
||||||
/// The actual on-boarding information. Only exists when one of the following is true:
|
/// 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.
|
/// - 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
|
/// - The full on-boarding information has not yet been provided and the parachain is not
|
||||||
/// yet due to be off-boarded.
|
/// yet due to be off-boarded.
|
||||||
pub Onboarding get(onboarding): map ParaIdOf<T> =>
|
pub Onboarding get(onboarding): map ParaId =>
|
||||||
Option<(LeasePeriodOf<T>, IncomingParachain<T::AccountId, T::Hash>)>;
|
Option<(LeasePeriodOf<T>, IncomingParachain<T::AccountId, T::Hash>)>;
|
||||||
|
|
||||||
/// Off-boarding account; currency held on deposit for the parachain gets placed here if the
|
/// 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.
|
/// 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;
|
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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +197,7 @@ decl_event!(
|
|||||||
AccountId = <T as system::Trait>::AccountId,
|
AccountId = <T as system::Trait>::AccountId,
|
||||||
BlockNumber = <T as system::Trait>::BlockNumber,
|
BlockNumber = <T as system::Trait>::BlockNumber,
|
||||||
LeasePeriod = LeasePeriodOf<T>,
|
LeasePeriod = LeasePeriodOf<T>,
|
||||||
ParaId = ParaIdOf<T>,
|
ParaId = ParaId,
|
||||||
Balance = BalanceOf<T>,
|
Balance = BalanceOf<T>,
|
||||||
{
|
{
|
||||||
/// A new lease period is beginning.
|
/// A new lease period is beginning.
|
||||||
@@ -281,7 +299,7 @@ decl_module! {
|
|||||||
/// - `amount` is the amount to bid to be held as deposit for the parachain should the
|
/// - `amount` is the amount to bid to be held as deposit for the parachain should the
|
||||||
/// bid win. This amount is held throughout the range.
|
/// bid win. This amount is held throughout the range.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
|
||||||
fn bid(origin,
|
pub fn bid(origin,
|
||||||
#[compact] sub: SubId,
|
#[compact] sub: SubId,
|
||||||
#[compact] auction_index: AuctionIndex,
|
#[compact] auction_index: AuctionIndex,
|
||||||
#[compact] first_slot: LeasePeriodOf<T>,
|
#[compact] first_slot: LeasePeriodOf<T>,
|
||||||
@@ -308,7 +326,7 @@ decl_module! {
|
|||||||
/// absolute lease period index value, not an auction-specific offset.
|
/// absolute lease period index value, not an auction-specific offset.
|
||||||
/// - `amount` is the amount to bid to be held as deposit for the parachain should the
|
/// - `amount` is the amount to bid to be held as deposit for the parachain should the
|
||||||
/// bid win. This amount is held throughout the range.
|
/// bid win. This amount is held throughout the range.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
|
||||||
fn bid_renew(origin,
|
fn bid_renew(origin,
|
||||||
#[compact] auction_index: AuctionIndex,
|
#[compact] auction_index: AuctionIndex,
|
||||||
#[compact] first_slot: LeasePeriodOf<T>,
|
#[compact] first_slot: LeasePeriodOf<T>,
|
||||||
@@ -316,7 +334,7 @@ decl_module! {
|
|||||||
#[compact] amount: BalanceOf<T>
|
#[compact] amount: BalanceOf<T>
|
||||||
) {
|
) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
let para_id = <ParaIdOf<T>>::try_from_account(&who)
|
let para_id = <ParaId>::try_from_account(&who)
|
||||||
.ok_or("account is not a parachain")?;
|
.ok_or("account is not a parachain")?;
|
||||||
let bidder = Bidder::Existing(para_id);
|
let bidder = Bidder::Existing(para_id);
|
||||||
Self::handle_bid(bidder, auction_index, first_slot, last_slot, amount)?;
|
Self::handle_bid(bidder, auction_index, first_slot, last_slot, amount)?;
|
||||||
@@ -328,10 +346,10 @@ decl_module! {
|
|||||||
///
|
///
|
||||||
/// - `dest` is the destination account to receive the parachain's deposit.
|
/// - `dest` is the destination account to receive the parachain's deposit.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
||||||
fn set_offboarding(origin, dest: <T::Lookup as StaticLookup>::Source) {
|
pub fn set_offboarding(origin, dest: <T::Lookup as StaticLookup>::Source) {
|
||||||
let who = ensure_signed(origin)?;
|
let who = ensure_signed(origin)?;
|
||||||
let dest = T::Lookup::lookup(dest)?;
|
let dest = T::Lookup::lookup(dest)?;
|
||||||
let para_id = <ParaIdOf<T>>::try_from_account(&who)
|
let para_id = <ParaId>::try_from_account(&who)
|
||||||
.ok_or("not a parachain origin")?;
|
.ok_or("not a parachain origin")?;
|
||||||
<Offboarding<T>>::insert(para_id, dest);
|
<Offboarding<T>>::insert(para_id, dest);
|
||||||
}
|
}
|
||||||
@@ -343,10 +361,10 @@ decl_module! {
|
|||||||
/// - `para_id` is the parachain ID allotted to the winning bidder.
|
/// - `para_id` is the parachain ID allotted to the winning bidder.
|
||||||
/// - `code_hash` is the hash of the parachain's Wasm validation function.
|
/// - `code_hash` is the hash of the parachain's Wasm validation function.
|
||||||
/// - `initial_head_data` is the parachain's initial head data.
|
/// - `initial_head_data` is the parachain's initial head data.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
|
||||||
pub fn fix_deploy_data(origin,
|
pub fn fix_deploy_data(origin,
|
||||||
#[compact] sub: SubId,
|
#[compact] sub: SubId,
|
||||||
#[compact] para_id: ParaIdOf<T>,
|
#[compact] para_id: ParaId,
|
||||||
code_hash: T::Hash,
|
code_hash: T::Hash,
|
||||||
initial_head_data: Vec<u8>
|
initial_head_data: Vec<u8>
|
||||||
) {
|
) {
|
||||||
@@ -375,7 +393,7 @@ decl_module! {
|
|||||||
/// - `para_id` is the parachain ID whose code will be elaborated.
|
/// - `para_id` is the parachain ID whose code will be elaborated.
|
||||||
/// - `code` is the preimage of the registered `code_hash` of `para_id`.
|
/// - `code` is the preimage of the registered `code_hash` of `para_id`.
|
||||||
#[weight = SimpleDispatchInfo::FixedNormal(5_000_000)]
|
#[weight = SimpleDispatchInfo::FixedNormal(5_000_000)]
|
||||||
fn elaborate_deploy_data(_origin, #[compact] para_id: ParaIdOf<T>, code: Vec<u8>) {
|
pub fn elaborate_deploy_data(_origin, #[compact] para_id: ParaId, code: Vec<u8>) {
|
||||||
let (starts, details) = <Onboarding<T>>::get(¶_id)
|
let (starts, details) = <Onboarding<T>>::get(¶_id)
|
||||||
.ok_or("parachain id not in onboarding")?;
|
.ok_or("parachain id not in onboarding")?;
|
||||||
if let IncomingParachain::Fixed{code_hash, initial_head_data} = details {
|
if let IncomingParachain::Fixed{code_hash, initial_head_data} = details {
|
||||||
@@ -388,7 +406,8 @@ decl_module! {
|
|||||||
// Should have already begun. Remove the on-boarding entry and register the
|
// Should have already begun. Remove the on-boarding entry and register the
|
||||||
// parachain for its immediate start.
|
// parachain for its immediate start.
|
||||||
<Onboarding<T>>::remove(¶_id);
|
<Onboarding<T>>::remove(¶_id);
|
||||||
let _ = T::Parachains::register_parachain(para_id, code, initial_head_data);
|
let _ = T::Parachains::
|
||||||
|
register_para(para_id, PARACHAIN_INFO, code, initial_head_data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err("deploy data not yet fixed")
|
return Err("deploy data not yet fixed")
|
||||||
@@ -399,7 +418,7 @@ decl_module! {
|
|||||||
|
|
||||||
impl<T: Trait> Module<T> {
|
impl<T: Trait> Module<T> {
|
||||||
/// Deposit currently held for a particular parachain that we administer.
|
/// Deposit currently held for a particular parachain that we administer.
|
||||||
fn deposit_held(para_id: &ParaIdOf<T>) -> BalanceOf<T> {
|
fn deposit_held(para_id: &ParaId) -> BalanceOf<T> {
|
||||||
<Deposits<T>>::get(para_id).into_iter().max().unwrap_or_else(Zero::zero)
|
<Deposits<T>>::get(para_id).into_iter().max().unwrap_or_else(Zero::zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,8 +512,14 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
// Add para IDs of any chains that will be newly deployed to our set of managed
|
// Add para IDs of any chains that will be newly deployed to our set of managed
|
||||||
// IDs.
|
// IDs.
|
||||||
<ManagedIds<T>>::mutate(|m| m.push(para_id));
|
ManagedIds::mutate(|ids|
|
||||||
|
if let Err(pos) = ids.binary_search(¶_id) {
|
||||||
|
ids.insert(pos, para_id)
|
||||||
|
} else {
|
||||||
|
// This can't happen as it's a winner being newly
|
||||||
|
// deployed and thus the para_id shouldn't already be being managed.
|
||||||
|
}
|
||||||
|
);
|
||||||
Self::deposit_event(RawEvent::WonDeploy(bidder.clone(), range, para_id, amount));
|
Self::deposit_event(RawEvent::WonDeploy(bidder.clone(), range, para_id, amount));
|
||||||
|
|
||||||
// Add a deployment record so we know to on-board them at the appropriate
|
// Add a deployment record so we know to on-board them at the appropriate
|
||||||
@@ -573,7 +598,7 @@ impl<T: Trait> Module<T> {
|
|||||||
Self::deposit_event(RawEvent::NewLeasePeriod(lease_period_index));
|
Self::deposit_event(RawEvent::NewLeasePeriod(lease_period_index));
|
||||||
// First, bump off old deposits and decommission any managed chains that are coming
|
// First, bump off old deposits and decommission any managed chains that are coming
|
||||||
// to a close.
|
// to a close.
|
||||||
<ManagedIds<T>>::mutate(|ids| {
|
ManagedIds::mutate(|ids| {
|
||||||
let new = ids.drain(..).filter(|id| {
|
let new = ids.drain(..).filter(|id| {
|
||||||
let mut d = <Deposits<T>>::get(id);
|
let mut d = <Deposits<T>>::get(id);
|
||||||
if !d.is_empty() {
|
if !d.is_empty() {
|
||||||
@@ -586,7 +611,7 @@ impl<T: Trait> Module<T> {
|
|||||||
// Only unregister it if it was actually registered in the first place.
|
// Only unregister it if it was actually registered in the first place.
|
||||||
// If the on-boarding entry still existed, then it was never actually
|
// If the on-boarding entry still existed, then it was never actually
|
||||||
// commissioned.
|
// commissioned.
|
||||||
let _ = T::Parachains::deregister_parachain(id.clone());
|
let _ = T::Parachains::deregister_para(id.clone());
|
||||||
}
|
}
|
||||||
// Return the full deposit to the off-boarding account.
|
// Return the full deposit to the off-boarding account.
|
||||||
T::Currency::deposit_creating(&<Offboarding<T>>::take(id), d[0]);
|
T::Currency::deposit_creating(&<Offboarding<T>>::take(id), d[0]);
|
||||||
@@ -628,7 +653,8 @@ impl<T: Trait> Module<T> {
|
|||||||
{
|
{
|
||||||
// The chain's deployment data is set; go ahead and register it, and remove the
|
// The chain's deployment data is set; go ahead and register it, and remove the
|
||||||
// now-redundant on-boarding entry.
|
// now-redundant on-boarding entry.
|
||||||
let _ = T::Parachains::register_parachain(para_id.clone(), code, initial_head_data);
|
let _ = T::Parachains::
|
||||||
|
register_para(para_id.clone(), PARACHAIN_INFO, code, initial_head_data);
|
||||||
// ^^ not much we can do if it fails for some reason.
|
// ^^ not much we can do if it fails for some reason.
|
||||||
<Onboarding<T>>::remove(para_id)
|
<Onboarding<T>>::remove(para_id)
|
||||||
}
|
}
|
||||||
@@ -644,7 +670,7 @@ impl<T: Trait> Module<T> {
|
|||||||
/// - `last_slot`: The last lease period index of the range to be bid on (inclusive).
|
/// - `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.
|
/// - `amount`: The total amount to be the bid for deposit over the range.
|
||||||
pub fn handle_bid(
|
pub fn handle_bid(
|
||||||
bidder: Bidder<T::AccountId, ParaIdOf<T>>,
|
bidder: Bidder<T::AccountId>,
|
||||||
auction_index: u32,
|
auction_index: u32,
|
||||||
first_slot: LeasePeriodOf<T>,
|
first_slot: LeasePeriodOf<T>,
|
||||||
last_slot: LeasePeriodOf<T>,
|
last_slot: LeasePeriodOf<T>,
|
||||||
@@ -735,7 +761,7 @@ impl<T: Trait> Module<T> {
|
|||||||
/// https://github.com/w3f/consensus/blob/master/NPoS/auctiondynamicthing.py
|
/// https://github.com/w3f/consensus/blob/master/NPoS/auctiondynamicthing.py
|
||||||
fn calculate_winners(
|
fn calculate_winners(
|
||||||
mut winning: WinningData<T>,
|
mut winning: WinningData<T>,
|
||||||
new_id: impl Fn() -> ParaIdOf<T>
|
new_id: impl Fn() -> ParaId
|
||||||
) -> WinnersData<T> {
|
) -> WinnersData<T> {
|
||||||
let winning_ranges = {
|
let winning_ranges = {
|
||||||
let mut best_winners_ending_at:
|
let mut best_winners_ending_at:
|
||||||
@@ -783,7 +809,6 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// tests for this module
|
/// tests for this module
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@@ -799,7 +824,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use srml_support::{impl_outer_origin, parameter_types, assert_ok, assert_noop};
|
use srml_support::{impl_outer_origin, parameter_types, assert_ok, assert_noop};
|
||||||
use balances;
|
use balances;
|
||||||
use primitives::parachain::Id as ParaId;
|
use primitives::parachain::{Id as ParaId, Info as ParaInfo};
|
||||||
|
|
||||||
impl_outer_origin! {
|
impl_outer_origin! {
|
||||||
pub enum Origin for Test {}
|
pub enum Origin for Test {}
|
||||||
@@ -866,16 +891,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestParachains;
|
pub struct TestParachains;
|
||||||
impl ParachainRegistrar<u64> for TestParachains {
|
impl Registrar<u64> for TestParachains {
|
||||||
type ParaId = ParaId;
|
fn new_id() -> ParaId {
|
||||||
fn new_id() -> Self::ParaId {
|
|
||||||
PARACHAIN_COUNT.with(|p| {
|
PARACHAIN_COUNT.with(|p| {
|
||||||
*p.borrow_mut() += 1;
|
*p.borrow_mut() += 1;
|
||||||
(*p.borrow() - 1).into()
|
(*p.borrow() - 1).into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn register_parachain(
|
fn register_para(
|
||||||
id: Self::ParaId,
|
id: ParaId,
|
||||||
|
_info: ParaInfo,
|
||||||
code: Vec<u8>,
|
code: Vec<u8>,
|
||||||
initial_head_data: Vec<u8>
|
initial_head_data: Vec<u8>
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
@@ -887,7 +912,7 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn deregister_parachain(id: Self::ParaId) -> Result<(), &'static str> {
|
fn deregister_para(id: ParaId) -> Result<(), &'static str> {
|
||||||
PARACHAINS.with(|p| {
|
PARACHAINS.with(|p| {
|
||||||
if !p.borrow().contains_key(&id.into_inner()) {
|
if !p.borrow().contains_key(&id.into_inner()) {
|
||||||
panic!("ID doesn't exist")
|
panic!("ID doesn't exist")
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use polkadot_runtime::{
|
|||||||
GenesisConfig, CouncilConfig, ElectionsConfig, DemocracyConfig, SystemConfig,
|
GenesisConfig, CouncilConfig, ElectionsConfig, DemocracyConfig, SystemConfig,
|
||||||
SessionConfig, StakingConfig, BalancesConfig, SessionKeys, TechnicalCommitteeConfig,
|
SessionConfig, StakingConfig, BalancesConfig, SessionKeys, TechnicalCommitteeConfig,
|
||||||
SudoConfig, IndicesConfig, StakerStatus, WASM_BINARY,
|
SudoConfig, IndicesConfig, StakerStatus, WASM_BINARY,
|
||||||
ClaimsConfig, ParachainsConfig
|
ClaimsConfig, ParachainsConfig, RegistrarConfig
|
||||||
};
|
};
|
||||||
use polkadot_runtime::constants::{currency::DOTS, time::*};
|
use polkadot_runtime::constants::{currency::DOTS, time::*};
|
||||||
use sr_primitives::Perbill;
|
use sr_primitives::Perbill;
|
||||||
@@ -151,6 +151,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
authority_discovery: Some(Default::default()),
|
authority_discovery: Some(Default::default()),
|
||||||
parachains: Some(ParachainsConfig {
|
parachains: Some(ParachainsConfig {
|
||||||
authorities: vec![],
|
authorities: vec![],
|
||||||
|
}),
|
||||||
|
registrar: Some(RegistrarConfig {
|
||||||
parachains: vec![],
|
parachains: vec![],
|
||||||
_phdata: Default::default(),
|
_phdata: Default::default(),
|
||||||
}),
|
}),
|
||||||
@@ -289,6 +291,8 @@ pub fn testnet_genesis(
|
|||||||
authority_discovery: Some(Default::default()),
|
authority_discovery: Some(Default::default()),
|
||||||
parachains: Some(ParachainsConfig {
|
parachains: Some(ParachainsConfig {
|
||||||
authorities: vec![],
|
authorities: vec![],
|
||||||
|
}),
|
||||||
|
registrar: Some(RegistrarConfig{
|
||||||
parachains: vec![],
|
parachains: vec![],
|
||||||
_phdata: Default::default(),
|
_phdata: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use super::MAX_TRANSACTIONS_SIZE;
|
|||||||
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use polkadot_primitives::{Block, Hash, BlockNumber};
|
use polkadot_primitives::{Block, Hash, BlockNumber};
|
||||||
use polkadot_primitives::parachain::Id as ParaId;
|
use polkadot_primitives::parachain::{Id as ParaId, CollatorId, Retriable};
|
||||||
|
|
||||||
/// Result type alias for block evaluation
|
/// Result type alias for block evaluation
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
@@ -66,7 +66,7 @@ pub fn evaluate_initial(
|
|||||||
_now: u64,
|
_now: u64,
|
||||||
parent_hash: &Hash,
|
parent_hash: &Hash,
|
||||||
parent_number: BlockNumber,
|
parent_number: BlockNumber,
|
||||||
_active_parachains: &[ParaId],
|
_active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
|
let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
|
||||||
a + Encode::encode(tx).len()
|
a + Encode::encode(tx).len()
|
||||||
|
|||||||
@@ -763,7 +763,7 @@ impl<C, TxApi> CreateProposal<C, TxApi> where
|
|||||||
self.believed_minimum_timestamp,
|
self.believed_minimum_timestamp,
|
||||||
&self.parent_hash,
|
&self.parent_hash,
|
||||||
self.parent_number,
|
self.parent_number,
|
||||||
&active_parachains,
|
&active_parachains[..],
|
||||||
).is_ok());
|
).is_ok());
|
||||||
|
|
||||||
Ok(new_block)
|
Ok(new_block)
|
||||||
|
|||||||
Reference in New Issue
Block a user