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 b2e9011ec8937d6c73e99292416c9692aeb30f73.

* 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: Gavin Wood <gavin@parity.io>
This commit is contained in:
Shawn Tabrizi
2021-02-18 23:20:18 -04:00
committed by GitHub
parent 006602eff2
commit a5defa7c7f
20 changed files with 654 additions and 698 deletions
@@ -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);
Initializer::on_finalize(1);
Configuration::initializer_on_new_session(&[], &[], &1);
Configuration::initializer_on_new_session(&[], &[]);
assert_eq!(Configuration::config(), old_config);
assert_eq!(<Configuration as Store>::PendingConfig::get(2), Some(config.clone()));
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())
});
}