mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 09:21:04 +00:00
7343c974a2
* Claims * Crowdloan * Runtime common * Parachains registrar * Impls * Purchase * Slots * parachains runtime mock * Use MockGenesisConfig in tests * Update runtime/common/src/claims.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
737 lines
21 KiB
Rust
737 lines
21 KiB
Rust
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
|
|
// This file is part of Polkadot.
|
|
|
|
// Polkadot is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Polkadot is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! Module to handle parathread/parachain registration and related fund management.
|
|
//! In essence this is a simple wrapper around `paras`.
|
|
|
|
use crate::WASM_MAGIC;
|
|
use sp_std::{prelude::*, result};
|
|
use frame_support::{
|
|
decl_storage, decl_module, decl_error, ensure,
|
|
dispatch::DispatchResult,
|
|
traits::{Get, Currency, ReservableCurrency},
|
|
};
|
|
use frame_system::{self, ensure_root, ensure_signed};
|
|
use primitives::v1::{
|
|
Id as ParaId, ValidationCode, HeadData,
|
|
};
|
|
use runtime_parachains::{
|
|
paras::{
|
|
self,
|
|
ParaGenesisArgs,
|
|
},
|
|
dmp, ump, hrmp,
|
|
ensure_parachain,
|
|
Origin,
|
|
};
|
|
|
|
type BalanceOf<T> =
|
|
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
|
|
|
|
pub trait Config: paras::Config + dmp::Config + ump::Config + hrmp::Config {
|
|
/// The aggregated origin type must support the `parachains` origin. We require that we can
|
|
/// infallibly convert between this origin and the system origin, but in reality, they're the
|
|
/// same type, we just can't express that to the Rust type system without writing a `where`
|
|
/// clause everywhere.
|
|
type Origin: From<<Self as frame_system::Config>::Origin>
|
|
+ Into<result::Result<Origin, <Self as Config>::Origin>>;
|
|
|
|
/// The system's currency for parathread payment.
|
|
type Currency: ReservableCurrency<Self::AccountId>;
|
|
|
|
/// The deposit to be paid to run a parathread.
|
|
type ParathreadDeposit: Get<BalanceOf<Self>>;
|
|
}
|
|
|
|
decl_storage! {
|
|
trait Store for Module<T: Config> as Registrar {
|
|
/// Whether parathreads are enabled or not.
|
|
ParathreadsRegistrationEnabled: bool;
|
|
|
|
/// Pending swap operations.
|
|
PendingSwap: map hasher(twox_64_concat) ParaId => Option<ParaId>;
|
|
|
|
/// Map of all registered parathreads/chains.
|
|
Paras get(fn paras): map hasher(twox_64_concat) ParaId => Option<bool>;
|
|
|
|
/// Users who have paid a parathread's deposit.
|
|
Debtors: map hasher(twox_64_concat) ParaId => T::AccountId;
|
|
}
|
|
}
|
|
|
|
decl_error! {
|
|
pub enum Error for Module<T: Config> {
|
|
/// Parachain already exists.
|
|
ParaAlreadyExists,
|
|
/// Invalid parachain ID.
|
|
InvalidChainId,
|
|
/// Invalid parathread ID.
|
|
InvalidThreadId,
|
|
/// Invalid para code size.
|
|
CodeTooLarge,
|
|
/// Invalid para head data size.
|
|
HeadDataTooLarge,
|
|
/// Parathreads registration is disabled.
|
|
ParathreadsRegistrationDisabled,
|
|
/// The validation code provided doesn't start with the Wasm file magic string.
|
|
DefinitelyNotWasm,
|
|
}
|
|
}
|
|
|
|
decl_module! {
|
|
pub struct Module<T: Config> for enum Call where origin: <T as frame_system::Config>::Origin {
|
|
type Error = Error<T>;
|
|
|
|
/// Register a parathread with given code for immediate use.
|
|
///
|
|
/// Must be sent from a Signed origin that is able to have `ParathreadDeposit` reserved.
|
|
/// `genesis_head` and `validation_code` are used to initalize the parathread's state.
|
|
#[weight = 0]
|
|
fn register_parathread(
|
|
origin,
|
|
id: ParaId,
|
|
genesis_head: HeadData,
|
|
validation_code: ValidationCode,
|
|
) -> DispatchResult {
|
|
let who = ensure_signed(origin)?;
|
|
|
|
ensure!(ParathreadsRegistrationEnabled::get(), Error::<T>::ParathreadsRegistrationDisabled);
|
|
ensure!(validation_code.0.starts_with(WASM_MAGIC), Error::<T>::DefinitelyNotWasm);
|
|
|
|
ensure!(!Paras::contains_key(id), Error::<T>::ParaAlreadyExists);
|
|
|
|
let outgoing = <paras::Module<T>>::outgoing_paras();
|
|
|
|
ensure!(outgoing.binary_search(&id).is_err(), Error::<T>::ParaAlreadyExists);
|
|
|
|
<T as Config>::Currency::reserve(&who, T::ParathreadDeposit::get())?;
|
|
<Debtors<T>>::insert(id, who);
|
|
|
|
Paras::insert(id, false);
|
|
|
|
let genesis = ParaGenesisArgs {
|
|
genesis_head,
|
|
validation_code,
|
|
parachain: false,
|
|
};
|
|
|
|
runtime_parachains::schedule_para_initialize::<T>(id, genesis);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Deregister a parathread and retreive the deposit.
|
|
///
|
|
/// Must be sent from a `Parachain` origin which is currently a parathread.
|
|
///
|
|
/// Ensure that before calling this that any funds you want emptied from the parathread's
|
|
/// account is moved out; after this it will be impossible to retreive them (without
|
|
/// governance intervention).
|
|
#[weight = 0]
|
|
fn deregister_parathread(origin) -> DispatchResult {
|
|
let id = ensure_parachain(<T as Config>::Origin::from(origin))?;
|
|
|
|
ensure!(ParathreadsRegistrationEnabled::get(), Error::<T>::ParathreadsRegistrationDisabled);
|
|
|
|
let is_parachain = Paras::take(id).ok_or(Error::<T>::InvalidChainId)?;
|
|
|
|
ensure!(!is_parachain, Error::<T>::InvalidThreadId);
|
|
|
|
let debtor = <Debtors<T>>::take(id);
|
|
let _ = <T as Config>::Currency::unreserve(&debtor, T::ParathreadDeposit::get());
|
|
|
|
runtime_parachains::schedule_para_cleanup::<T>(id);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[weight = 0]
|
|
fn enable_parathread_registration(origin) -> DispatchResult {
|
|
ensure_root(origin)?;
|
|
|
|
ParathreadsRegistrationEnabled::put(true);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[weight = 0]
|
|
fn disable_parathread_registration(origin) -> DispatchResult {
|
|
ensure_root(origin)?;
|
|
|
|
ParathreadsRegistrationEnabled::put(false);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
|
|
/// Swap a parachain with another parachain or parathread. The origin must be a `Parachain`.
|
|
/// The swap will happen only if there is already an opposite swap pending. If there is not,
|
|
/// the swap will be stored in the pending swaps map, ready for a later confirmatory swap.
|
|
///
|
|
/// The `ParaId`s remain mapped to the same head data and code so external code can rely on
|
|
/// `ParaId` to be a long-term identifier of a notional "parachain". However, their
|
|
/// scheduling info (i.e. whether they're a parathread or parachain), auction information
|
|
/// and the auction deposit are switched.
|
|
#[weight = 0]
|
|
fn swap(origin, other: ParaId) {
|
|
let id = ensure_parachain(<T as Config>::Origin::from(origin))?;
|
|
|
|
if PendingSwap::get(other) == Some(id) {
|
|
// Remove intention to swap.
|
|
PendingSwap::remove(other);
|
|
|
|
Paras::mutate(id, |i|
|
|
Paras::mutate(other, |j|
|
|
sp_std::mem::swap(i, j)
|
|
)
|
|
);
|
|
|
|
<Debtors<T>>::mutate(id, |i|
|
|
<Debtors<T>>::mutate(other, |j|
|
|
sp_std::mem::swap(i, j)
|
|
)
|
|
);
|
|
} else {
|
|
PendingSwap::insert(id, other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Config> Module<T> {
|
|
/// Register a parachain with given code. Must be called by root.
|
|
/// Fails if given ID is already used.
|
|
pub fn register_parachain(
|
|
id: ParaId,
|
|
genesis_head: HeadData,
|
|
validation_code: ValidationCode,
|
|
) -> DispatchResult {
|
|
ensure!(!Paras::contains_key(id), Error::<T>::ParaAlreadyExists);
|
|
ensure!(validation_code.0.starts_with(WASM_MAGIC), Error::<T>::DefinitelyNotWasm);
|
|
|
|
let outgoing = <paras::Module<T>>::outgoing_paras();
|
|
|
|
ensure!(outgoing.binary_search(&id).is_err(), Error::<T>::ParaAlreadyExists);
|
|
|
|
Paras::insert(id, true);
|
|
|
|
let genesis = ParaGenesisArgs {
|
|
genesis_head,
|
|
validation_code,
|
|
parachain: true,
|
|
};
|
|
|
|
runtime_parachains::schedule_para_initialize::<T>(id, genesis);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Deregister a parachain with the given ID. Must be called by root.
|
|
pub fn deregister_parachain(id: ParaId) -> DispatchResult {
|
|
let is_parachain = Paras::take(id).ok_or(Error::<T>::InvalidChainId)?;
|
|
|
|
ensure!(is_parachain, Error::<T>::InvalidChainId);
|
|
|
|
runtime_parachains::schedule_para_cleanup::<T>(id);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use sp_io::TestExternalities;
|
|
use sp_core::H256;
|
|
use sp_runtime::{
|
|
traits::{
|
|
BlakeTwo256, IdentityLookup, Extrinsic as ExtrinsicT,
|
|
}, testing::{UintAuthorityId, TestXt}, Perbill, curve::PiecewiseLinear,
|
|
};
|
|
use primitives::v1::{
|
|
Balance, BlockNumber, Header, Signature, AuthorityDiscoveryId, ValidatorIndex,
|
|
};
|
|
use frame_system::limits;
|
|
use frame_support::{
|
|
traits::{Randomness, OnInitialize, OnFinalize},
|
|
assert_ok, parameter_types,
|
|
};
|
|
use keyring::Sr25519Keyring;
|
|
use runtime_parachains::{initializer, configuration, inclusion, session_info, scheduler, dmp, ump, hrmp};
|
|
use frame_support::traits::OneSessionHandler;
|
|
use crate::paras_registrar;
|
|
|
|
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
|
type Block = frame_system::mocking::MockBlock<Test>;
|
|
|
|
frame_support::construct_runtime!(
|
|
pub enum Test where
|
|
Block = Block,
|
|
NodeBlock = Block,
|
|
UncheckedExtrinsic = UncheckedExtrinsic,
|
|
{
|
|
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
|
Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
|
|
Parachains: paras::{Module, Origin, Call, Storage, Config<T>},
|
|
Inclusion: inclusion::{Module, Call, Storage, Event<T>},
|
|
Registrar: paras_registrar::{Module, Call, Storage},
|
|
Staking: pallet_staking::{Module, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
|
|
Session: pallet_session::{Module, Call, Storage, Event, Config<T>},
|
|
Initializer: initializer::{Module, Call, Storage},
|
|
}
|
|
);
|
|
|
|
pallet_staking_reward_curve::build! {
|
|
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
|
|
min_inflation: 0_025_000,
|
|
max_inflation: 0_100_000,
|
|
ideal_stake: 0_500_000,
|
|
falloff: 0_050_000,
|
|
max_piece_count: 40,
|
|
test_precision: 0_005_000,
|
|
);
|
|
}
|
|
|
|
const NORMAL_RATIO: Perbill = Perbill::from_percent(75);
|
|
parameter_types! {
|
|
pub const BlockHashCount: u32 = 250;
|
|
pub BlockWeights: limits::BlockWeights =
|
|
limits::BlockWeights::with_sensible_defaults(4 * 1024 * 1024, NORMAL_RATIO);
|
|
pub BlockLength: limits::BlockLength =
|
|
limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO);
|
|
}
|
|
|
|
impl frame_system::Config for Test {
|
|
type BaseCallFilter = ();
|
|
type Origin = Origin;
|
|
type Call = Call;
|
|
type Index = u64;
|
|
type BlockNumber = BlockNumber;
|
|
type Hash = H256;
|
|
type Hashing = BlakeTwo256;
|
|
type AccountId = u64;
|
|
type Lookup = IdentityLookup<u64>;
|
|
type Header = Header;
|
|
type Event = Event;
|
|
type BlockHashCount = BlockHashCount;
|
|
type DbWeight = ();
|
|
type BlockWeights = BlockWeights;
|
|
type BlockLength = BlockLength;
|
|
type Version = ();
|
|
type PalletInfo = PalletInfo;
|
|
type AccountData = pallet_balances::AccountData<u128>;
|
|
type OnNewAccount = ();
|
|
type OnKilledAccount = ();
|
|
type SystemWeightInfo = ();
|
|
type SS58Prefix = ();
|
|
}
|
|
|
|
impl<C> frame_system::offchain::SendTransactionTypes<C> for Test where
|
|
Call: From<C>,
|
|
{
|
|
type OverarchingCall = Call;
|
|
type Extrinsic = TestXt<Call, ()>;
|
|
}
|
|
|
|
parameter_types! {
|
|
pub const ExistentialDeposit: Balance = 1;
|
|
}
|
|
|
|
impl pallet_balances::Config for Test {
|
|
type Balance = u128;
|
|
type DustRemoval = ();
|
|
type Event = Event;
|
|
type ExistentialDeposit = ExistentialDeposit;
|
|
type AccountStore = System;
|
|
type MaxLocks = ();
|
|
type WeightInfo = ();
|
|
}
|
|
|
|
parameter_types!{
|
|
pub const SlashDeferDuration: pallet_staking::EraIndex = 7;
|
|
pub const AttestationPeriod: BlockNumber = 100;
|
|
pub const MinimumPeriod: u64 = 3;
|
|
pub const SessionsPerEra: sp_staking::SessionIndex = 6;
|
|
pub const BondingDuration: pallet_staking::EraIndex = 28;
|
|
pub const MaxNominatorRewardedPerValidator: u32 = 64;
|
|
}
|
|
|
|
parameter_types! {
|
|
pub const Period: BlockNumber = 1;
|
|
pub const Offset: BlockNumber = 0;
|
|
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
|
|
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
|
|
}
|
|
|
|
impl pallet_session::Config for Test {
|
|
type SessionManager = ();
|
|
type Keys = UintAuthorityId;
|
|
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
|
|
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
|
|
type SessionHandler = pallet_session::TestSessionHandler;
|
|
type Event = Event;
|
|
type ValidatorId = u64;
|
|
type ValidatorIdOf = ();
|
|
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
|
|
type WeightInfo = ();
|
|
}
|
|
|
|
parameter_types! {
|
|
pub const MaxHeadDataSize: u32 = 100;
|
|
pub const MaxCodeSize: u32 = 100;
|
|
|
|
pub const ValidationUpgradeFrequency: BlockNumber = 10;
|
|
pub const ValidationUpgradeDelay: BlockNumber = 2;
|
|
pub const SlashPeriod: BlockNumber = 50;
|
|
pub const ElectionLookahead: BlockNumber = 0;
|
|
pub const StakingUnsignedPriority: u64 = u64::max_value() / 2;
|
|
}
|
|
|
|
impl pallet_staking::Config for Test {
|
|
type RewardRemainder = ();
|
|
type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
|
|
type Event = Event;
|
|
type Currency = pallet_balances::Module<Test>;
|
|
type Slash = ();
|
|
type Reward = ();
|
|
type SessionsPerEra = SessionsPerEra;
|
|
type BondingDuration = BondingDuration;
|
|
type SlashDeferDuration = SlashDeferDuration;
|
|
type SlashCancelOrigin = frame_system::EnsureRoot<Self::AccountId>;
|
|
type SessionInterface = Self;
|
|
type UnixTime = pallet_timestamp::Module<Test>;
|
|
type RewardCurve = RewardCurve;
|
|
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
|
type NextNewSession = Session;
|
|
type ElectionLookahead = ElectionLookahead;
|
|
type Call = Call;
|
|
type UnsignedPriority = StakingUnsignedPriority;
|
|
type MaxIterations = ();
|
|
type MinSolutionScoreBump = ();
|
|
type OffchainSolutionWeightLimit = ();
|
|
type WeightInfo = ();
|
|
}
|
|
|
|
impl pallet_timestamp::Config for Test {
|
|
type Moment = u64;
|
|
type OnTimestampSet = ();
|
|
type MinimumPeriod = MinimumPeriod;
|
|
type WeightInfo = ();
|
|
}
|
|
|
|
impl dmp::Config for Test {}
|
|
|
|
impl ump::Config for Test {
|
|
type UmpSink = ();
|
|
}
|
|
|
|
impl hrmp::Config for Test {
|
|
type Origin = Origin;
|
|
type Currency = pallet_balances::Module<Test>;
|
|
}
|
|
|
|
impl pallet_session::historical::Config for Test {
|
|
type FullIdentification = pallet_staking::Exposure<u64, Balance>;
|
|
type FullIdentificationOf = pallet_staking::ExposureOf<Self>;
|
|
}
|
|
|
|
// This is needed for a custom `AccountId` type which is `u64` in testing here.
|
|
pub mod test_keys {
|
|
use sp_core::crypto::KeyTypeId;
|
|
|
|
pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");
|
|
|
|
mod app {
|
|
use super::super::Inclusion;
|
|
use sp_application_crypto::{app_crypto, sr25519};
|
|
|
|
app_crypto!(sr25519, super::KEY_TYPE);
|
|
|
|
impl sp_runtime::traits::IdentifyAccount for Public {
|
|
type AccountId = u64;
|
|
|
|
fn into_account(self) -> Self::AccountId {
|
|
let id = self.0.clone().into();
|
|
Inclusion::validators().iter().position(|b| *b == id).unwrap() as u64
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type ReporterId = app::Public;
|
|
}
|
|
|
|
impl paras::Config for Test {
|
|
type Origin = Origin;
|
|
}
|
|
|
|
impl configuration::Config for Test { }
|
|
|
|
pub struct TestRewardValidators;
|
|
|
|
impl inclusion::RewardValidators for TestRewardValidators {
|
|
fn reward_backing(_: impl IntoIterator<Item = ValidatorIndex>) { }
|
|
fn reward_bitfields(_: impl IntoIterator<Item = ValidatorIndex>) { }
|
|
}
|
|
|
|
impl inclusion::Config for Test {
|
|
type Event = Event;
|
|
type RewardValidators = TestRewardValidators;
|
|
}
|
|
|
|
impl session_info::AuthorityDiscoveryConfig for Test {
|
|
fn authorities() -> Vec<AuthorityDiscoveryId> {
|
|
Vec::new()
|
|
}
|
|
}
|
|
|
|
impl session_info::Config for Test { }
|
|
|
|
pub struct TestRandomness;
|
|
|
|
impl Randomness<H256> for TestRandomness {
|
|
fn random(_subject: &[u8]) -> H256 {
|
|
Default::default()
|
|
}
|
|
}
|
|
|
|
impl initializer::Config for Test {
|
|
type Randomness = TestRandomness;
|
|
}
|
|
|
|
impl scheduler::Config for Test { }
|
|
|
|
type Extrinsic = TestXt<Call, ()>;
|
|
|
|
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Test where
|
|
Call: From<LocalCall>,
|
|
{
|
|
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
|
|
call: Call,
|
|
_public: test_keys::ReporterId,
|
|
_account: <Test as frame_system::Config>::AccountId,
|
|
nonce: <Test as frame_system::Config>::Index,
|
|
) -> Option<(Call, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
|
|
Some((call, (nonce, ())))
|
|
}
|
|
}
|
|
|
|
impl frame_system::offchain::SigningTypes for Test {
|
|
type Public = test_keys::ReporterId;
|
|
type Signature = Signature;
|
|
}
|
|
|
|
parameter_types! {
|
|
pub const ParathreadDeposit: Balance = 10;
|
|
pub const QueueSize: usize = 2;
|
|
pub const MaxRetries: u32 = 3;
|
|
}
|
|
|
|
impl Config for Test {
|
|
type Origin = Origin;
|
|
type Currency = pallet_balances::Module<Test>;
|
|
type ParathreadDeposit = ParathreadDeposit;
|
|
}
|
|
|
|
fn new_test_ext() -> TestExternalities {
|
|
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
|
|
|
let authority_keys = [
|
|
Sr25519Keyring::Alice,
|
|
Sr25519Keyring::Bob,
|
|
Sr25519Keyring::Charlie,
|
|
Sr25519Keyring::Dave,
|
|
Sr25519Keyring::Eve,
|
|
Sr25519Keyring::Ferdie,
|
|
Sr25519Keyring::One,
|
|
Sr25519Keyring::Two,
|
|
];
|
|
|
|
let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();
|
|
|
|
pallet_balances::GenesisConfig::<Test> {
|
|
balances,
|
|
}.assimilate_storage(&mut t).unwrap();
|
|
|
|
// stashes are the index.
|
|
let session_keys: Vec<_> = authority_keys.iter().enumerate()
|
|
.map(|(i, _k)| (i as u64, i as u64, UintAuthorityId(i as u64)))
|
|
.collect();
|
|
|
|
pallet_session::GenesisConfig::<Test> {
|
|
keys: session_keys,
|
|
}.assimilate_storage(&mut t).unwrap();
|
|
|
|
t.into()
|
|
}
|
|
|
|
fn run_to_block(n: BlockNumber) {
|
|
// NOTE that this function only simulates modules of interest. Depending on new module may
|
|
// require adding it here.
|
|
println!("Running until block {}", n);
|
|
while System::block_number() < n {
|
|
let b = System::block_number();
|
|
|
|
if System::block_number() > 1 {
|
|
println!("Finalizing {}", System::block_number());
|
|
System::on_finalize(System::block_number());
|
|
Initializer::on_finalize(System::block_number());
|
|
}
|
|
// Session change every 3 blocks.
|
|
if (b + 1) % 3 == 0 {
|
|
println!("New session at {}", System::block_number());
|
|
Initializer::on_new_session(
|
|
false,
|
|
Vec::new().into_iter(),
|
|
Vec::new().into_iter(),
|
|
);
|
|
}
|
|
System::set_block_number(b + 1);
|
|
println!("Initializing {}", System::block_number());
|
|
System::on_initialize(System::block_number());
|
|
Initializer::on_initialize(System::block_number());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn basic_setup_works() {
|
|
new_test_ext().execute_with(|| {
|
|
assert_eq!(PendingSwap::get(&ParaId::from(0u32)), None);
|
|
assert_eq!(Paras::get(&ParaId::from(0u32)), None);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn register_deregister_chain_works() {
|
|
new_test_ext().execute_with(|| {
|
|
run_to_block(1);
|
|
|
|
assert_ok!(Registrar::enable_parathread_registration(
|
|
Origin::root(),
|
|
));
|
|
run_to_block(2);
|
|
|
|
assert_ok!(Registrar::register_parachain(
|
|
2u32.into(),
|
|
vec![3; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
));
|
|
|
|
let orig_bal = Balances::free_balance(&3u64);
|
|
|
|
// Register a new parathread
|
|
assert_ok!(Registrar::register_parathread(
|
|
Origin::signed(3u64),
|
|
8u32.into(),
|
|
vec![3; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
));
|
|
|
|
// deposit should be taken (reserved)
|
|
assert_eq!(Balances::free_balance(3u64) + ParathreadDeposit::get(), orig_bal);
|
|
assert_eq!(Balances::reserved_balance(3u64), ParathreadDeposit::get());
|
|
|
|
run_to_block(3);
|
|
|
|
assert_ok!(Registrar::deregister_parachain(2u32.into()));
|
|
|
|
assert_ok!(Registrar::deregister_parathread(
|
|
runtime_parachains::Origin::Parachain(8u32.into()).into()
|
|
));
|
|
|
|
// reserved balance should be returned.
|
|
assert_eq!(Balances::free_balance(3u64), orig_bal);
|
|
assert_eq!(Balances::reserved_balance(3u64), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn swap_handles_funds_correctly() {
|
|
new_test_ext().execute_with(|| {
|
|
run_to_block(1);
|
|
|
|
assert_ok!(Registrar::enable_parathread_registration(
|
|
Origin::root(),
|
|
));
|
|
run_to_block(2);
|
|
|
|
let initial_1_balance = Balances::free_balance(1);
|
|
let initial_2_balance = Balances::free_balance(2);
|
|
|
|
// User 1 register a new parathread
|
|
assert_ok!(Registrar::register_parathread(
|
|
Origin::signed(1),
|
|
8u32.into(),
|
|
vec![1; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
));
|
|
|
|
assert_ok!(Registrar::register_parachain(
|
|
2u32.into(),
|
|
vec![1; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
));
|
|
|
|
run_to_block(9);
|
|
|
|
// Swap the parachain and parathread
|
|
assert_ok!(Registrar::swap(runtime_parachains::Origin::Parachain(2u32.into()).into(), 8u32.into()));
|
|
assert_ok!(Registrar::swap(runtime_parachains::Origin::Parachain(8u32.into()).into(), 2u32.into()));
|
|
|
|
// Deregister a parathread that was originally a parachain
|
|
assert_ok!(Registrar::deregister_parathread(runtime_parachains::Origin::Parachain(2u32.into()).into()));
|
|
|
|
run_to_block(12);
|
|
|
|
// Funds are correctly returned
|
|
assert_eq!(Balances::free_balance(1), initial_1_balance);
|
|
assert_eq!(Balances::free_balance(2), initial_2_balance);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn cannot_register_until_para_is_cleaned_up() {
|
|
new_test_ext().execute_with(|| {
|
|
run_to_block(2);
|
|
|
|
assert_ok!(Registrar::register_parachain(
|
|
1u32.into(),
|
|
vec![1; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
));
|
|
|
|
run_to_block(4);
|
|
|
|
assert_ok!(Registrar::deregister_parachain(1u32.into()));
|
|
run_to_block(5);
|
|
|
|
assert!(Registrar::register_parachain(
|
|
1u32.into(),
|
|
vec![1; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
).is_err());
|
|
|
|
// The session will be changed on the 6th block, as part of finalization. The change
|
|
// will be observed on the 7th.
|
|
run_to_block(7);
|
|
assert_ok!(Registrar::register_parachain(
|
|
1u32.into(),
|
|
vec![1; 3].into(),
|
|
WASM_MAGIC.to_vec().into(),
|
|
));
|
|
});
|
|
}
|
|
}
|