Unverified Commit afb6daa7 authored by Shawn Tabrizi's avatar Shawn Tabrizi Committed by GitHub
Browse files

Session Delayed Para Changes / Actions Queue (#2406)

* initial implementation of lifecycles and upgrades

* clean up a bit

* fix doc comment

* more rigid lifecycle checks

* include paras which are transitioning, and lifecycle query

* format guide

* update api

* update guide

* explicit outgoing state, fix genesis

* handle outgoing with transitioning paras

* do not include transitioning paras in identifier

* Update roadmap/implementers-guide/src/runtime/paras.md

* Update roadmap/implementers-guide/src/runtime/paras.md

* Update roadmap/implementers-guide/src/runtime/paras.md

* Apply suggestions from code review

* Use matches macro

* Correct terms

* Apply suggestions from code review

* actions queue

* Revert "actions queue"

This reverts commit b2e9011e

.

* collapse onboarding state

* starting actions queue

* consolidate actions queue

* schedule para initialize result

* more actions queue for upgrade/downgrade

* clean up with fully implemented actions queue

* fix tests

* fix scheduler tests

* fix hrmp tests

* fix test

* doc fixes

* fix hrmp test w/ valid para

* Update paras.md

* fix paras registrar

* Update propose_parachain.rs

* fix merge

* Introduce "shared" module

* fix rococo build

* fix up and use shared

* guide updates

* add shared config to common tests

* add shared to test-runtime

* remove println

* fix note
Co-authored-by: default avatarGavin Wood <gavin@parity.io>
parent 10b0d793
Pipeline #124707 passed with stages
in 33 minutes and 10 seconds
......@@ -15,11 +15,15 @@ There is some functionality of the relay chain relating to parachains that we al
We will split the logic of the runtime up into these modules:
* Initializer: manage initialization order of the other modules.
* Shared: manages shared storage and configurations for other modules.
* Configuration: manage configuration and configuration updates in a non-racy manner.
* Paras: manage chain-head and validation code for parachains and parathreads.
* Scheduler: manages parachain and parathread scheduling as well as validator assignments.
* Inclusion: handles the inclusion and availability of scheduled parachains and parathreads.
* Validity: handles secondary checks and dispute resolution for included, available parablocks.
* Hrmp: handles horizontal messages between paras.
* Ump: Handles upward messages from a para to the relay chain.
* Dmp: Handles downward messages from the relay chain to the para.
The [Initializer module](initializer.md) is special - it's responsible for handling the initialization logic of the other modules to ensure that the correct initialization order and related invariants are maintained. The other modules won't specify a on-initialize logic, but will instead expose a special semi-private routine that the initialization module will call. The other modules are relatively straightforward and perform the roles described above.
......
......@@ -36,9 +36,6 @@ PendingAvailabilityCommitments: map ParaId => CandidateCommitments;
/// The current validators, by their parachain session keys.
Validators: Vec<ValidatorId>;
/// The current session index.
CurrentSessionIndex: SessionIndex;
```
## Session Change
......@@ -46,7 +43,6 @@ CurrentSessionIndex: SessionIndex;
1. Clear out all candidates pending availability.
1. Clear out all validator bitfields.
1. Update `Validators` with the validators from the session change notification.
1. Update `CurrentSessionIndex` with the session index from the session change notification.
## Routines
......
# Paras Module
The Paras module is responsible for storing information on parachains and parathreads. Registered
parachains and parathreads cannot change except at session boundaries. This is primarily to ensure
that the number and meaning of bits required for the availability bitfields does not change except at session
boundaries.
parachains and parathreads cannot change except at session boundaries and after at least a full
session has passed. This is primarily to ensure that the number and meaning of bits required for the
availability bitfields does not change except at session boundaries.
It's also responsible for managing parachain validation code upgrades as well as maintaining
availability of old parachain code and its pruning.
......@@ -63,9 +63,9 @@ pub enum ParaLifecycle {
/// Para is a Parachain.
Parachain,
/// Para is a Parathread which is upgrading to a Parachain.
UpgradingToParachain,
UpgradingParathread,
/// Para is a Parachain which is downgrading to a Parathread.
DowngradingToParathread,
DowngradingParachain,
/// Parathread is being offboarded.
OutgoingParathread,
/// Parachain is being offboarded.
......@@ -82,7 +82,7 @@ state of the para using the `ParaLifecycle` enum.
None Parathread Parachain
+ + +
| | |
| (Session Delay) | |
| (2 Session Delay) | |
| | |
+----------------------->+ |
| Onboarding | |
......@@ -91,10 +91,10 @@ None Parathread Parachain
| Onboarding | |
| | |
| +------------------------->+
| | UpgradingToParachain |
| | UpgradingParathread |
| | |
| +<-------------------------+
| | DowngradingToParathread |
| | DowngradingParachain |
| | |
|<-----------------------+ |
| OutgoingParathread | |
......@@ -137,38 +137,31 @@ PastCodePruning: Vec<(ParaId, BlockNumber)>;
FutureCodeUpgrades: map ParaId => Option<BlockNumber>;
/// The actual future code of a para.
FutureCode: map ParaId => Option<ValidationCode>;
/// Upcoming paras (chains and threads). These are only updated on session change. Corresponds to an
/// entry in the upcoming-genesis map. Ordered ascending by ParaId.
UpcomingParas: Vec<ParaId>;
/// The actions to perform during the start of a specific session index.
ActionsQueue: map SessionIndex => Vec<ParaId>;
/// Upcoming paras instantiation arguments.
UpcomingParasGenesis: map ParaId => Option<ParaGenesisArgs>;
/// Paras that are to be cleaned up at the end of the session. Ordered ascending by ParaId.
OutgoingParas: Vec<ParaId>;
/// Existing Parathreads that should upgrade to be a Parachain. Ordered ascending by ParaId.
UpcomingUpgrades: Vec<ParaId>;
/// Existing Parachains that should downgrade to be a Parathread. Ordered ascending by ParaId.
UpcomingDowngrades: Vec<ParaId>;
```
## Session Change
1. Clean up outgoing paras.
1. This means removing the entries under `Heads`, `ValidationCode`, `FutureCodeUpgrades`, and
`FutureCode`. An according entry should be added to `PastCode`, `PastCodeMeta`, and
`PastCodePruning` using the outgoing `ParaId` and removed `ValidationCode` value. This is
because any outdated validation code must remain available on-chain for a determined amount of
blocks, and validation code outdated by de-registering the para is still subject to that
invariant.
1. Apply all incoming paras by initializing the `Heads` and `ValidationCode` using the genesis
parameters.
1. Amend the `Parachains` list and `ParaLifecycle` to reflect changes in registered parachains.
1. Amend the `ParaLifecycle` set to reflect changes in registered parathreads.
1. Upgrade all parathreads that should become parachains, updating the `Parachains` list and
`ParaLifecycle`.
1. Downgrade all parachains that should become parathreads, updating the `Parachains` list and
`ParaLifecycle`.
1. Return list of outgoing paras to the initializer for use by other modules.
1. Execute all queued actions for paralifecycle changes:
1. Clean up outgoing paras.
1. This means removing the entries under `Heads`, `ValidationCode`, `FutureCodeUpgrades`, and
`FutureCode`. An according entry should be added to `PastCode`, `PastCodeMeta`, and
`PastCodePruning` using the outgoing `ParaId` and removed `ValidationCode` value. This is
because any outdated validation code must remain available on-chain for a determined amount
of blocks, and validation code outdated by de-registering the para is still subject to that
invariant.
1. Apply all incoming paras by initializing the `Heads` and `ValidationCode` using the genesis
parameters.
1. Amend the `Parachains` list and `ParaLifecycle` to reflect changes in registered parachains.
1. Amend the `ParaLifecycle` set to reflect changes in registered parathreads.
1. Upgrade all parathreads that should become parachains, updating the `Parachains` list and
`ParaLifecycle`.
1. Downgrade all parachains that should become parathreads, updating the `Parachains` list and
`ParaLifecycle`.
1. Return list of outgoing paras to the initializer for use by other modules.
## Initialization
......@@ -179,11 +172,9 @@ UpcomingDowngrades: Vec<ParaId>;
* `schedule_para_initialize(ParaId, ParaGenesisArgs)`: Schedule a para to be initialized at the next
session. Noop if para is already registered in the system with some `ParaLifecycle`.
* `schedule_para_cleanup(ParaId)`: Schedule a para to be cleaned up at the next session.
* `schedule_parathread_upgrade(ParaId)`: Schedule a parathread to be upgraded to a parachain. Noop
if `ParaLifecycle` is not `Parathread`.
* `schedule_para_cleanup(ParaId)`: Schedule a para to be cleaned up after the next full session.
* `schedule_parathread_upgrade(ParaId)`: Schedule a parathread to be upgraded to a parachain.
* `schedule_parachain_downgrade(ParaId)`: Schedule a parachain to be downgraded to a parathread.
Noop if `ParaLifecycle` is not `Parachain`.
* `schedule_code_upgrade(ParaId, ValidationCode, expected_at: BlockNumber)`: Schedule a future code
upgrade of the given parachain, to be applied after inclusion of a block of the same parachain
executed in the context of a relay-chain block with number >= `expected_at`.
......@@ -197,8 +188,8 @@ UpcomingDowngrades: Vec<ParaId>;
current, or (with certain choices of `assume_intermediate`) future code. `assume_intermediate`, if
provided, must be before `at`. If the validation code has been pruned, this will return `None`.
* `lifecycle(ParaId) -> Option<ParaLifecycle>`: Return the `ParaLifecycle` of a para.
* `is_parachain(ParaId) -> bool`: Returns true if the para ID references any live parachain, including
those which may be transitioning to a parathread in the future.
* `is_parachain(ParaId) -> bool`: Returns true if the para ID references any live parachain,
including those which may be transitioning to a parathread in the future.
* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread,
including those which may be transitioning to a parachain in the future.
* `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live parathread
......
# Shared Module
This module is responsible for managing shared storage and configuration for other modules.
It is important that other pallets are able to use the Shared Module, so it should not have a
dependency on any other modules in the Parachains Runtime.
For the moment, it is used exclusively to track the current session index across the Parachains
Runtime system, and when it should be allowed to schedule future changes to Paras or Configurations.
## Constants
```rust
// `SESSION_DELAY` is used to delay any changes to Paras registration or configurations.
// Wait until the session index is 2 larger then the current index to apply any changes,
// which guarantees that at least one full session has passed before any changes are applied.
pub(crate) const SESSION_DELAY: SessionIndex = 2;
```
## Storage
```rust
// The current session index within the Parachains Runtime system.
CurrentSessionIndex: SessionIndex;
```
## Initialization
The Shared Module currently has no initialization routines.
The Shared Module is initialized directly after the Configuration module, but before all other
modules. It is important to update the Shared Module before any other module since its state may be
used within the logic of other modules, and it is important that the state is consistent across
them.
## Session Change
During a session change, the Shared Module receives and stores the current Session Index for that
block through the Session Change Notification.
This information is used in the:
* Configuration Module: For delaying updates to configurations until at lease one full session has
passed.
* Paras Module: For delaying updates to paras until at least one full session has passed.
## Finalization
The Shared Module currently has no finalization routines.
## Functions
* `scheduled_sessions() -> SessionIndex`: Return the next session index where updates to the
Parachains Runtime system would be safe to apply.
* `set_session_index(SessionIndex)`: For tests. Set the current session index in the Shared Module.
......@@ -88,6 +88,8 @@ decl_error! {
ParathreadsRegistrationDisabled,
/// The validation code provided doesn't start with the Wasm file magic string.
DefinitelyNotWasm,
/// Cannot deregister para
CannotDeregister,
}
}
......@@ -113,22 +115,18 @@ decl_module! {
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,
};
ensure!(paras::Module::<T>::can_schedule_para_initialize(&id, &genesis), Error::<T>::ParaAlreadyExists);
<T as Config>::Currency::reserve(&who, T::ParathreadDeposit::get())?;
runtime_parachains::schedule_para_initialize::<T>(id, genesis);
<Debtors<T>>::insert(id, who);
Paras::insert(id, false);
// Checked this shouldn't fail above.
let _ = runtime_parachains::schedule_para_initialize::<T>(id, genesis);
Ok(())
}
......@@ -146,14 +144,16 @@ decl_module! {
ensure!(ParathreadsRegistrationEnabled::get(), Error::<T>::ParathreadsRegistrationDisabled);
let is_parachain = Paras::take(id).ok_or(Error::<T>::InvalidChainId)?;
let is_parachain = Paras::get(id).ok_or(Error::<T>::InvalidChainId)?;
ensure!(!is_parachain, Error::<T>::InvalidThreadId);
runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CannotDeregister)?;
let debtor = <Debtors<T>>::take(id);
let _ = <T as Config>::Currency::unreserve(&debtor, T::ParathreadDeposit::get());
runtime_parachains::schedule_para_cleanup::<T>(id);
Paras::remove(&id);
PendingSwap::remove(&id);
Ok(())
}
......@@ -176,7 +176,6 @@ decl_module! {
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.
......@@ -222,30 +221,27 @@ impl<T: Config> Module<T> {
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);
runtime_parachains::schedule_para_initialize::<T>(id, genesis).map_err(|_| Error::<T>::ParaAlreadyExists)?;
Paras::insert(id, true);
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)?;
let is_parachain = Paras::get(id).ok_or(Error::<T>::InvalidChainId)?;
ensure!(is_parachain, Error::<T>::InvalidChainId);
runtime_parachains::schedule_para_cleanup::<T>(id);
runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CannotDeregister)?;
Paras::remove(&id);
PendingSwap::remove(&id);
Ok(())
}
......@@ -267,10 +263,13 @@ mod tests {
use frame_system::limits;
use frame_support::{
traits::{Randomness, OnInitialize, OnFinalize},
assert_ok, parameter_types,
assert_ok, assert_noop, parameter_types,
};
use keyring::Sr25519Keyring;
use runtime_parachains::{initializer, configuration, inclusion, session_info, scheduler, dmp, ump, hrmp};
use runtime_parachains::{
initializer, configuration, inclusion, session_info, scheduler, dmp, ump, hrmp, shared,
ParaLifecycle,
};
use frame_support::traits::OneSessionHandler;
use crate::paras_registrar;
......@@ -309,7 +308,7 @@ mod tests {
parameter_types! {
pub const BlockHashCount: u32 = 250;
pub BlockWeights: limits::BlockWeights =
limits::BlockWeights::with_sensible_defaults(4 * 1024 * 1024, NORMAL_RATIO);
frame_system::limits::BlockWeights::simple_max(1024);
pub BlockLength: limits::BlockLength =
limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO);
}
......@@ -370,7 +369,7 @@ mod tests {
}
parameter_types! {
pub const Period: BlockNumber = 1;
pub const Period: BlockNumber = 3;
pub const Offset: BlockNumber = 0;
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
......@@ -432,6 +431,8 @@ mod tests {
type WeightInfo = ();
}
impl shared::Config for Test {}
impl dmp::Config for Test {}
impl ump::Config for Test {
......@@ -590,7 +591,7 @@ mod tests {
Initializer::on_finalize(System::block_number());
}
// Session change every 3 blocks.
if (b + 1) % 3 == 0 {
if (b + 1) % Period::get() == 0 {
println!("New session at {}", System::block_number());
Initializer::on_new_session(
false,
......@@ -601,6 +602,7 @@ mod tests {
System::set_block_number(b + 1);
println!("Initializing {}", System::block_number());
System::on_initialize(System::block_number());
Session::on_initialize(System::block_number());
Initializer::on_initialize(System::block_number());
}
}
......@@ -643,7 +645,7 @@ mod tests {
assert_eq!(Balances::free_balance(3u64) + ParathreadDeposit::get(), orig_bal);
assert_eq!(Balances::reserved_balance(3u64), ParathreadDeposit::get());
run_to_block(3);
run_to_block(10);
assert_ok!(Registrar::deregister_parachain(2u32.into()));
......@@ -690,10 +692,12 @@ mod tests {
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()));
run_to_block(15);
// Deregister a parathread that was originally a parachain
assert_ok!(Registrar::deregister_parathread(runtime_parachains::Origin::Parachain(2u32.into()).into()));
run_to_block(12);
run_to_block(21);
// Funds are correctly returned
assert_eq!(Balances::free_balance(1), initial_1_balance);
......@@ -712,20 +716,26 @@ mod tests {
WASM_MAGIC.to_vec().into(),
));
run_to_block(4);
// 2 session changes to fully onboard.
run_to_block(12);
assert_eq!(Parachains::lifecycle(1u32.into()), Some(ParaLifecycle::Parachain));
assert_ok!(Registrar::deregister_parachain(1u32.into()));
run_to_block(5);
run_to_block(13);
assert_eq!(Parachains::lifecycle(1u32.into()), Some(ParaLifecycle::OffboardingParachain));
assert!(Registrar::register_parachain(
assert_noop!(Registrar::register_parachain(
1u32.into(),
vec![1; 3].into(),
WASM_MAGIC.to_vec().into(),
).is_err());
), Error::<Test>::ParaAlreadyExists);
// Need 2 session changes to see the effect, which takes place by block 13.
run_to_block(18);
// 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!(Parachains::lifecycle(1u32.into()).is_none());
assert_ok!(Registrar::register_parachain(
1u32.into(),
vec![1; 3].into(),
......
......@@ -40,11 +40,15 @@ decl_error! {
pub enum Error for Module<T: Config> {
/// The specified parachain or parathread is not registered.
ParaDoesntExist,
/// The specified parachain or parathread is already registered.
ParaAlreadyExists,
/// A DMP message couldn't be sent because it exceeds the maximum size allowed for a downward
/// message.
ExceedsMaxMessageSize,
/// The validation code provided doesn't start with the Wasm file magic string.
DefinitelyNotWasm,
/// Could not schedule para cleanup.
CouldntCleanup,
}
}
......@@ -62,7 +66,7 @@ decl_module! {
) -> DispatchResult {
ensure_root(origin)?;
ensure!(genesis.validation_code.0.starts_with(WASM_MAGIC), Error::<T>::DefinitelyNotWasm);
runtime_parachains::schedule_para_initialize::<T>(id, genesis);
runtime_parachains::schedule_para_initialize::<T>(id, genesis).map_err(|_| Error::<T>::ParaAlreadyExists)?;
Ok(())
}
......@@ -70,7 +74,7 @@ decl_module! {
#[weight = (1_000, DispatchClass::Operational)]
pub fn sudo_schedule_para_cleanup(origin, id: ParaId) -> DispatchResult {
ensure_root(origin)?;
runtime_parachains::schedule_para_cleanup::<T>(id);
runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CouldntCleanup)?;
Ok(())
}
......
......@@ -29,6 +29,7 @@ use frame_support::{
use parity_scale_codec::{Encode, Decode};
use frame_system::ensure_root;
use sp_runtime::traits::Zero;
use crate::shared;
/// All configuration of the runtime with respect to parachains and parathreads.
#[derive(Clone, Encode, Decode, PartialEq, sp_core::RuntimeDebug)]
......@@ -231,14 +232,14 @@ impl<BlockNumber: Zero> HostConfiguration<BlockNumber> {
}
}
pub trait Config: frame_system::Config { }
pub trait Config: frame_system::Config + shared::Config { }
decl_storage! {
trait Store for Module<T: Config> as Configuration {
/// The active configuration for the current session.
ActiveConfig get(fn config) config(): HostConfiguration<T::BlockNumber>;
/// Pending configuration (if any) for the next session.
PendingConfig: Option<HostConfiguration<T::BlockNumber>>;
PendingConfig: map hasher(twox_64_concat) SessionIndex => Option<HostConfiguration<T::BlockNumber>>;
}
add_extra_genesis {
build(|config: &Self| {
......@@ -646,12 +647,21 @@ impl<T: Config> Module<T> {
pub(crate) fn initializer_finalize() { }
/// Called by the initializer to note that a new session has started.
pub(crate) fn initializer_on_new_session(_validators: &[ValidatorId], _queued: &[ValidatorId]) {
if let Some(pending) = <Self as Store>::PendingConfig::take() {
pub(crate) fn initializer_on_new_session(
_validators: &[ValidatorId],
_queued: &[ValidatorId],
session_index: &SessionIndex,
) {
if let Some(pending) = <Self as Store>::PendingConfig::take(session_index) {
<Self as Store>::ActiveConfig::set(pending);
}
}
/// Return the session index that should be used for any future scheduled changes.
fn scheduled_session() -> SessionIndex {
shared::Module::<T>::scheduled_session()
}
// NOTE: Explicitly tell rustc not to inline this because otherwise heuristics note the incoming
// closure making it's attractive to inline. However, in this case, we will end up with lots of
// duplicated code (making this function to show up in the top of heaviest functions) only for
......@@ -660,11 +670,12 @@ impl<T: Config> Module<T> {
fn update_config_member(
updater: impl FnOnce(&mut HostConfiguration<T::BlockNumber>) -> bool,
) {
let pending = <Self as Store>::PendingConfig::get();
let scheduled_session = Self::scheduled_session();
let pending = <Self as Store>::PendingConfig::get(scheduled_session);
let mut prev = pending.unwrap_or_else(Self::config);
if updater(&mut prev) {
<Self as Store>::PendingConfig::set(Some(prev));
<Self as Store>::PendingConfig::insert(scheduled_session, prev);
}
}
}
......@@ -672,32 +683,32 @@ impl<T: Config> Module<T> {
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Initializer, Configuration, Origin};
use crate::mock::{new_test_ext, Configuration, Origin};
use frame_support::traits::{OnFinalize, OnInitialize};
use frame_support::assert_ok;
#[test]
fn config_changes_on_session_boundary() {
fn config_changes_after_2_session_boundary() {
new_test_ext(Default::default()).execute_with(|| {
let old_config = Configuration::config();
let mut config = old_config.clone();
config.validation_upgrade_delay = 100;
assert!(old_config != config);
<Configuration as Store>::PendingConfig::set(Some(config.clone()));
Initializer::on_initialize(1);
assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100));
assert_eq!(Configuration::config(), old_config);
assert_eq!(<Configuration as Store>::PendingConfig::get(), Some(config.clone()));
assert_eq!(<Configuration as Store>::PendingConfig::get(1), None);
Configuration::initializer_on_new_session(&[], &[], &1);
Initializer::on_finalize(1);
assert_eq!(Configuration::config(), old_config);
assert_eq!(<Configuration as Store>::PendingConfig::get(2), Some(config.clone()));
Configuration::initializer_on_new_session(&[], &[]);
Configuration::initializer_on_new_session(&[], &[], &2);
assert_eq!(Configuration::config(), config);
assert!(<Configuration as Store>::PendingConfig::get().is_none());
assert_eq!(<Configuration as Store>::PendingConfig::get(3), None);
})
}
......@@ -743,7 +754,7 @@ mod tests {
hrmp_max_message_num_per_candidate: 20,
};
assert!(<Configuration as Store>::PendingConfig::get().is_none());
assert!(<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY).is_none());
Configuration::set_validation_upgrade_frequency(
Origin::root(), new_config.validation_upgrade_frequency,
......@@ -865,7 +876,7 @@ mod tests {
new_config.hrmp_max_message_num_per_candidate,
).unwrap();
assert_eq!(<Configuration as Store>::PendingConfig::get(), Some(new_config));
assert_eq!(<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY), Some(new_config));
})
}
......@@ -880,7 +891,7 @@ mod tests {
fn setting_config_to_same_as_current_is_noop() {
new_test_ext(Default::default()).execute_with(|| {
Configuration::set_validation_upgrade_delay(Origin::root(), Default::default()).unwrap();
assert!(<Configuration as Store>::PendingConfig::get().is_none())
assert!(<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY).is_none())
});
}
......