Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ceb0bee
initial implementation of lifecycles and upgrades
shawntabrizi Jan 30, 2021
ca2e930
clean up a bit
shawntabrizi Jan 30, 2021
f03cf68
fix doc comment
shawntabrizi Jan 31, 2021
8ab27f0
more rigid lifecycle checks
shawntabrizi Jan 31, 2021
af59148
include paras which are transitioning, and lifecycle query
shawntabrizi Jan 31, 2021
a154cf8
format guide
shawntabrizi Jan 31, 2021
bfc96a1
update api
shawntabrizi Jan 31, 2021
fdde35f
update guide
shawntabrizi Jan 31, 2021
623746c
explicit outgoing state, fix genesis
shawntabrizi Jan 31, 2021
2eb5e19
handle outgoing with transitioning paras
shawntabrizi Feb 1, 2021
80c7b64
do not include transitioning paras in identifier
shawntabrizi Feb 1, 2021
ee07f80
Update roadmap/implementers-guide/src/runtime/paras.md
gavofyork Feb 2, 2021
ea62e00
Update roadmap/implementers-guide/src/runtime/paras.md
gavofyork Feb 2, 2021
1289e39
Update roadmap/implementers-guide/src/runtime/paras.md
gavofyork Feb 2, 2021
c26b42e
Apply suggestions from code review
gavofyork Feb 2, 2021
26d6c99
Use matches macro
gavofyork Feb 2, 2021
4f26659
Correct terms
gavofyork Feb 2, 2021
a785985
Apply suggestions from code review
gavofyork Feb 2, 2021
b2e9011
actions queue
shawntabrizi Feb 3, 2021
f56777c
Revert "actions queue"
shawntabrizi Feb 3, 2021
7455165
collapse onboarding state
shawntabrizi Feb 4, 2021
f63b087
starting actions queue
shawntabrizi Feb 4, 2021
45cc0c6
consolidate actions queue
shawntabrizi Feb 8, 2021
e1df6f7
schedule para initialize result
shawntabrizi Feb 8, 2021
7ebfa65
more actions queue for upgrade/downgrade
shawntabrizi Feb 8, 2021
077a550
clean up with fully implemented actions queue
shawntabrizi Feb 8, 2021
516d182
fix tests
shawntabrizi Feb 8, 2021
bf74d5f
fix scheduler tests
shawntabrizi Feb 8, 2021
53a42fa
fix hrmp tests
shawntabrizi Feb 9, 2021
b0a1444
Merge branch 'master' into shawntabrizi-para-session-delay
shawntabrizi Feb 9, 2021
c14b17e
fix test
shawntabrizi Feb 9, 2021
17b6128
doc fixes
shawntabrizi Feb 9, 2021
c3aa6ea
fix hrmp test w/ valid para
shawntabrizi Feb 9, 2021
3df71fe
Update paras.md
shawntabrizi Feb 9, 2021
27cb18e
fix paras registrar
shawntabrizi Feb 9, 2021
92d456f
Merge branch 'master' into shawntabrizi-para-session-delay
shawntabrizi Feb 9, 2021
8b724e5
Update propose_parachain.rs
shawntabrizi Feb 9, 2021
fd4bb23
Merge branch 'master' into shawntabrizi-para-session-delay
shawntabrizi Feb 15, 2021
9342f21
fix merge
shawntabrizi Feb 15, 2021
3fbaa20
Introduce "shared" module
shawntabrizi Feb 16, 2021
fd959ab
fix rococo build
shawntabrizi Feb 16, 2021
b340613
fix up and use shared
shawntabrizi Feb 16, 2021
e6b79e7
guide updates
shawntabrizi Feb 16, 2021
40b05a4
add shared config to common tests
shawntabrizi Feb 16, 2021
44fb36e
add shared to test-runtime
shawntabrizi Feb 16, 2021
9da4b9e
Merge branch 'master' into shawntabrizi-para-session-delay
shawntabrizi Feb 16, 2021
62cead5
remove println
shawntabrizi Feb 18, 2021
442f0fb
fix note
shawntabrizi Feb 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
initial implementation of lifecycles and upgrades
  • Loading branch information
shawntabrizi committed Jan 30, 2021
commit ceb0bee1c8b59069242930261fa78da18659d27e
22 changes: 22 additions & 0 deletions runtime/parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ mod util;
#[cfg(test)]
mod mock;

use parity_scale_codec::{Encode, Decode};
use sp_core::RuntimeDebug;

pub use origin::{Origin, ensure_parachain};

/// Schedule a para to be initialized at the start of the next session with the given genesis data.
Expand All @@ -65,3 +68,22 @@ where
<ump::Module<T>>::schedule_para_cleanup(id);
<hrmp::Module<T>>::schedule_para_cleanup(id);
}

/// The possible states of a para, to take into account delayed lifecycle changes.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
pub enum ParaLifecycle {
/// Para ID is new and is onboarding as a Parathread.
OnboardingAsParathread,
/// Para ID is new and is onboarding as a Parachain.
OnboardingAsParachain,
/// Para ID is a Parathread.
Parathread,
/// Para ID is a Parachain.
Parachain,
/// Para ID is a Parathread which is upgrading to a Parachain.
UpgradingToParachain,
/// Para ID is a Parachain which is downgrading to a Parathread.
DowngradingToParathread,
/// Para ID is being offboarded.
Outgoing,
}
173 changes: 153 additions & 20 deletions runtime/parachains/src/paras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use frame_support::{
weights::Weight,
};
use parity_scale_codec::{Encode, Decode};
use crate::{configuration, initializer::SessionChangeNotification};
use crate::{configuration, initializer::SessionChangeNotification, ParaLifecycle};
use sp_core::RuntimeDebug;

#[cfg(feature = "std")]
Expand Down Expand Up @@ -180,8 +180,8 @@ decl_storage! {
trait Store for Module<T: Config> 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 current lifecycle of a all known Para IDs.
ParaLifecycles: map hasher(twox_64_concat) ParaId => Option<ParaLifecycle>;
/// The head-data of every registered para.
Heads get(fn para_head): map hasher(twox_64_concat) ParaId => Option<HeadData>;
/// The validation code of every live para.
Expand All @@ -208,13 +208,17 @@ decl_storage! {
FutureCode: map hasher(twox_64_concat) ParaId => Option<ValidationCode>;

/// Upcoming paras (chains and threads). These are only updated on session change. Corresponds to an
/// entry in the upcoming-genesis map.
/// entry in the upcoming-genesis map. Ordered.
UpcomingParas get(fn upcoming_paras): Vec<ParaId>;
/// Upcoming paras instantiation arguments.
UpcomingParasGenesis: map hasher(twox_64_concat) ParaId => Option<ParaGenesisArgs>;
/// Paras that are to be cleaned up at the end of the session.
OutgoingParas get(fn outgoing_paras): Vec<ParaId>;

/// Existing Parathreads that should upgrade to be a Parachain.
UpcomingUpgrades: Vec<ParaId>;
/// Existing Parachains that should downgrade to be a Parathread.
UpcomingDowngrades: Vec<ParaId>;
}
add_extra_genesis {
config(paras): Vec<(ParaId, ParaGenesisArgs)>;
Expand Down Expand Up @@ -268,6 +272,8 @@ impl<T: Config> Module<T> {
let now = <frame_system::Module<T>>::block_number();
let mut parachains = Self::clean_up_outgoing(now);
Self::apply_incoming(&mut parachains);
Self::apply_upgrades(&mut parachains);
Self::apply_downgrades(&mut parachains);
<Self as Store>::Parachains::set(parachains);
}

Expand All @@ -279,13 +285,12 @@ impl<T: Config> 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);
<Self as Store>::FutureCodeUpgrades::remove(&outgoing_para);
<Self as Store>::FutureCode::remove(&outgoing_para);
ParaLifecycles::remove(&outgoing_para);

let removed_code = <Self as Store>::CurrentCode::take(&outgoing_para);
if let Some(removed_code) = removed_code {
Expand All @@ -307,17 +312,45 @@ impl<T: Config> Module<T> {

if genesis_data.parachain {
if let Err(i) = parachains.binary_search(&upcoming_para) {
ParaLifecycles::insert(&upcoming_para, ParaLifecycle::Parachain);
parachains.insert(i, upcoming_para);
}
} else {
<Self as Store>::Parathreads::insert(&upcoming_para, ());
ParaLifecycles::insert(&upcoming_para, ParaLifecycle::Parathread);
}

<Self as Store>::Heads::insert(&upcoming_para, genesis_data.genesis_head);
<Self as Store>::CurrentCode::insert(&upcoming_para, genesis_data.validation_code);
}
}

/// Take an existing parathread and upgrade it to be a parachain.
fn apply_upgrades(parachains: &mut Vec<ParaId>) {
let upgrades = UpcomingUpgrades::take();
for para in upgrades {
ParaLifecycles::mutate(&para, |v| {
if *v == Some(ParaLifecycle::UpgradingToParachain) {
if let Err(i) = parachains.binary_search(&para) {
ParaLifecycles::insert(&para, ParaLifecycle::Parachain);
parachains.insert(i, para);
}
*v = Some(ParaLifecycle::Parachain);
}
});
}
}

/// Take an existing parachain and downgrade it to be a parathread. Update the list of parachains.
fn apply_downgrades(parachains: &mut Vec<ParaId>) {
let downgrades = UpcomingDowngrades::take();
for para in downgrades {
if let Ok(i) = parachains.binary_search(&para) {
parachains.remove(i);
ParaLifecycles::insert(&para, ParaLifecycle::Parathread);
}
}
}

// note replacement of the code of para with given `id`, which occured in the
// context of the given relay-chain block number. provide the replaced code.
//
Expand Down Expand Up @@ -412,6 +445,12 @@ impl<T: Config> Module<T> {
return weight;
}

if genesis.parachain {
ParaLifecycles::insert(&id, ParaLifecycle::OnboardingAsParachain);
} else {
ParaLifecycles::insert(&id, ParaLifecycle::OnboardingAsParathread);
}

UpcomingParasGenesis::insert(&id, &genesis);

T::DbWeight::get().reads_writes(1, 2)
Expand All @@ -423,9 +462,10 @@ impl<T: Config> Module<T> {
match v.binary_search(&id) {
Ok(i) => {
v.remove(i);
UpcomingParasGenesis::remove(id);
UpcomingParasGenesis::remove(&id);
ParaLifecycles::remove(&id);
// If a para was only in the pending state it should not be moved to `Outgoing`
return T::DbWeight::get().reads_writes(2, 2);
return T::DbWeight::get().reads_writes(2, 3);
}
Err(_) => T::DbWeight::get().reads_writes(1, 0),
}
Expand All @@ -436,14 +476,69 @@ impl<T: Config> Module<T> {
Ok(_) => T::DbWeight::get().reads_writes(1, 0),
Err(i) => {
v.insert(i, id);
T::DbWeight::get().reads_writes(1, 1)
ParaLifecycles::insert(&id, ParaLifecycle::Outgoing);
T::DbWeight::get().reads_writes(1, 2)
}
}
});

outgoing_weight + upcoming_weight
}

#[allow(dead_code)]
pub(crate) fn schedule_para_upgrade(id: ParaId) -> Weight {
if ParaLifecycles::get(&id) != Some(ParaLifecycle::Parathread) {
let weight = T::DbWeight::get().reads_writes(1, 0);
return weight;
}

let dup = UpcomingUpgrades::mutate(|v| {
match v.binary_search(&id) {
Ok(_) => true,
Err(i) => {
v.insert(i, id);
false
}
}
});

ParaLifecycles::insert(&id, ParaLifecycle::UpgradingToParachain);

if dup {
let weight = T::DbWeight::get().reads_writes(2, 1);
return weight;
}

T::DbWeight::get().reads_writes(2, 2)
}

#[allow(dead_code)]
pub(crate) fn schedule_para_downgrade(id: ParaId) -> Weight {
if ParaLifecycles::get(&id) != Some(ParaLifecycle::Parachain) {
let weight = T::DbWeight::get().reads_writes(1, 0);
return weight;
}

let dup = UpcomingDowngrades::mutate(|v| {
match v.binary_search(&id) {
Ok(_) => true,
Err(i) => {
v.insert(i, id);
false
}
}
});

ParaLifecycles::insert(&id, ParaLifecycle::DowngradingToParathread);

if dup {
let weight = T::DbWeight::get().reads_writes(2, 1);
return weight;
}

T::DbWeight::get().reads_writes(2, 2)
}

/// 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`
Expand Down Expand Up @@ -543,13 +638,30 @@ impl<T: Config> Module<T> {

/// Returns whether the given ID refers to a valid para.
pub fn is_valid_para(id: ParaId) -> bool {
Self::parachains().binary_search(&id).is_ok()
|| Self::is_parathread(id)
match ParaLifecycles::get(&id) {
Some(ParaLifecycle::Parachain) |
Some(ParaLifecycle::Parathread) |
Some(ParaLifecycle::UpgradingToParachain) |
Some(ParaLifecycle::DowngradingToParathread)
=> true,
_ => false,
}
}

/// Whether a para ID corresponds to any live parathread.
pub(crate) fn is_parathread(id: ParaId) -> bool {
Parathreads::get(&id).is_some()
pub fn is_parachain(id: ParaId) -> bool {
match ParaLifecycles::get(&id) {
Some(ParaLifecycle::Parachain) => true,
_ => false,
}
}

/// Whether a para ID corresponds to any live parathread.
pub fn is_parathread(id: ParaId) -> bool {
match ParaLifecycles::get(&id) {
Some(ParaLifecycle::Parathread) => true,
_ => false,
}
}

/// The block number of the last scheduled upgrade of the requested para. Includes future upgrades
Expand Down Expand Up @@ -1122,23 +1234,33 @@ mod tests {
);

assert_eq!(<Paras as Store>::UpcomingParas::get(), vec![c, b, a]);
assert!(<Paras as Store>::Parathreads::get(&a).is_none());

// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::OnboardingAsParathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::OnboardingAsParachain));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::OnboardingAsParachain));

// 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());

// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::OnboardingAsParathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::OnboardingAsParachain));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::OnboardingAsParachain));


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());
// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::Parathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::Parachain));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::Parachain));

assert_eq!(Paras::current_code(&a), Some(vec![2].into()));
assert_eq!(Paras::current_code(&b), Some(vec![1].into()));
Expand Down Expand Up @@ -1183,15 +1305,23 @@ mod tests {
);

assert_eq!(<Paras as Store>::UpcomingParas::get(), vec![c, b, a]);
assert!(<Paras as Store>::Parathreads::get(&a).is_none());

// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::OnboardingAsParathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::OnboardingAsParachain));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::OnboardingAsParachain));


// 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());

// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::OnboardingAsParathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::OnboardingAsParachain));
assert_eq!(ParaLifecycles::get(&c), Some(ParaLifecycle::OnboardingAsParachain));

Paras::schedule_para_cleanup(c);

Expand All @@ -1202,7 +1332,10 @@ mod tests {
assert_eq!(<Paras as Store>::UpcomingParas::get(), Vec::new());
assert!(<Paras as Store>::UpcomingParasGenesis::get(a).is_none());

assert!(<Paras as Store>::Parathreads::get(&a).is_some());
// Lifecycle is tracked correctly
assert_eq!(ParaLifecycles::get(&a), Some(ParaLifecycle::Parathread));
assert_eq!(ParaLifecycles::get(&b), Some(ParaLifecycle::Parachain));
assert_eq!(ParaLifecycles::get(&c), None);

assert_eq!(Paras::current_code(&a), Some(vec![2].into()));
assert_eq!(Paras::current_code(&b), Some(vec![1].into()));
Expand Down