Scheduler Module (#1162)

* scheduler module skeleton

* update scheduler skeleton to match latest version of guide

* better session change notification

* add mock randomness and fix test compilation

* shuffle validators into groups

* finish implementing session change logic for scheduler

* tweak core assignment type to track retries of parathread

* reframe queued parathread core as offset

* implement initialzation and finalization routines

* implement parathread claim queuing

* implement core_para

* implement the group_validators routine and fix errors

* add a reason for freeing cores

* implement `schedule` function

* add some docs to the scheduled function

* implement `occupied` helper

* implement availability predicate

* fix some warnings

* integrate scheduler into initializer

* integrate scheduler into mock module

* avoid conflict with Substrate's scheduler storage

* add parathreads index to paras module

* implement parathreads map in paras module

* add is_parathread to paras

* test adding parathread claim

* test that you cannot add claims when no parathread cores exist

* check session change parathread queue pruning

* test validator shuffling

* add allow_unused to scheduler items

* add test for scheduling

* add some more tests for scheduling logic

* test core rotation

* check parathread claim pruning after retries

* add bound notes

* Apply suggestions from code review

Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>

* more suggestions from review

* test availability predicate, add box to please compiler

* add changes to guide

Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
This commit is contained in:
Robert Habermeier
2020-06-11 15:15:30 -04:00
committed by GitHub
parent 053bfc2d0c
commit 04c8603042
10 changed files with 1637 additions and 29 deletions
+24 -7
View File
@@ -27,7 +27,7 @@ use sp_std::prelude::*;
use sp_std::marker::PhantomData;
use sp_runtime::traits::One;
use primitives::{
parachain::{ValidatorId, Id as ParaId, ValidationCode, HeadData},
parachain::{Id as ParaId, ValidationCode, HeadData},
};
use frame_support::{
decl_storage, decl_module, decl_error,
@@ -35,7 +35,7 @@ use frame_support::{
weights::Weight,
};
use codec::{Encode, Decode};
use crate::configuration;
use crate::{configuration, initializer::SessionChangeNotification};
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
@@ -159,11 +159,11 @@ impl<N: Ord + Copy> ParaPastCodeMeta<N> {
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ParaGenesisArgs {
/// The initial head data to use.
genesis_head: HeadData,
pub genesis_head: HeadData,
/// The initial validation code to use.
validation_code: ValidationCode,
pub validation_code: ValidationCode,
/// True if parachain, false if parathread.
parachain: bool,
pub parachain: bool,
}
@@ -171,6 +171,8 @@ decl_storage! {
trait Store for Module<T: Trait> as Paras {
/// All parachains. Ordered ascending by ParaId. Parathreads are not included.
Parachains get(fn parachains): Vec<ParaId>;
/// All parathreads.
Parathreads: map hasher(twox_64_concat) ParaId => Option<()>;
/// The head-data of every registered para.
Heads get(fn parachain_head): map hasher(twox_64_concat) ParaId => Option<HeadData>;
/// The validation code of every live para.
@@ -253,7 +255,7 @@ impl<T: Trait> 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]) {
pub(crate) fn initializer_on_new_session(_notification: &SessionChangeNotification<T::BlockNumber>) {
let now = <system::Module<T>>::block_number();
let mut parachains = Self::clean_up_outgoing(now);
Self::apply_incoming(&mut parachains);
@@ -268,6 +270,8 @@ impl<T: Trait> Module<T> {
for outgoing_para in outgoing {
if let Ok(i) = parachains.binary_search(&outgoing_para) {
parachains.remove(i);
} else {
<Self as Store>::Parathreads::remove(&outgoing_para);
}
<Self as Store>::Heads::remove(&outgoing_para);
@@ -296,6 +300,8 @@ impl<T: Trait> Module<T> {
if let Err(i) = parachains.binary_search(&upcoming_para) {
parachains.insert(i, upcoming_para);
}
} else {
<Self as Store>::Parathreads::insert(&upcoming_para, ());
}
<Self as Store>::Heads::insert(&upcoming_para, genesis_data.genesis_head);
@@ -515,6 +521,11 @@ impl<T: Trait> Module<T> {
}
}
}
/// Whether a para ID corresponds to any live parathread.
pub(crate) fn is_parathread(id: ParaId) -> bool {
Parathreads::get(&id).is_some()
}
}
#[cfg(test)]
@@ -536,7 +547,7 @@ mod tests {
System::set_block_number(b + 1);
if new_session.as_ref().map_or(false, |v| v.contains(&(b + 1))) {
Paras::initializer_on_new_session(&[], &[]);
Paras::initializer_on_new_session(&Default::default());
}
Paras::initializer_initialize(b + 1);
}
@@ -1040,18 +1051,24 @@ mod tests {
);
assert_eq!(<Paras as Store>::UpcomingParas::get(), vec![c, b, a]);
assert!(<Paras as Store>::Parathreads::get(&a).is_none());
// run to block without session change.
run_to_block(2, None);
assert_eq!(Paras::parachains(), Vec::new());
assert_eq!(<Paras as Store>::UpcomingParas::get(), vec![c, b, a]);
assert!(<Paras as Store>::Parathreads::get(&a).is_none());
run_to_block(3, Some(vec![3]));
assert_eq!(Paras::parachains(), vec![c, b]);
assert_eq!(<Paras as Store>::UpcomingParas::get(), Vec::new());
assert!(<Paras as Store>::Parathreads::get(&a).is_some());
assert_eq!(Paras::current_code(&a), Some(vec![2].into()));
assert_eq!(Paras::current_code(&b), Some(vec![1].into()));
assert_eq!(Paras::current_code(&c), Some(vec![3].into()));