From 35f60b1e90145714730d372b5067d9c392884ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 15 Aug 2020 01:51:03 +0200 Subject: [PATCH] Add support for scheduling an upgrade without checks --- parachain-upgrade/src/lib.rs | 57 +++++++++++-------- .../contracts-runtime/src/lib.rs | 2 +- rococo-parachains/runtime/src/lib.rs | 2 +- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/parachain-upgrade/src/lib.rs b/parachain-upgrade/src/lib.rs index fc943fbfa7..06a9ba3025 100644 --- a/parachain-upgrade/src/lib.rs +++ b/parachain-upgrade/src/lib.rs @@ -37,7 +37,7 @@ use cumulus_primitives::{ use frame_support::{ decl_error, decl_event, decl_module, decl_storage, ensure, storage, weights::DispatchClass, }; -use frame_system::ensure_none; +use frame_system::{ensure_none, ensure_root}; use parachain::primitives::RelayChainBlockNumber; use sp_core::storage::well_known_keys; use sp_inherents::{InherentData, InherentIdentifier, ProvideInherent}; @@ -79,30 +79,18 @@ decl_module! { // TODO: figure out a better weight than this #[weight = (0, DispatchClass::Operational)] pub fn schedule_upgrade(origin, validation_function: Vec) { - // TODO: in the future, we can't rely on a superuser existing - // on-chain who can just wave their hands and make this happen. - // Instead, this should hook into the democracy pallet and check - // that a validation function upgrade has been approved; potentially, - // it should even trigger the validation function upgrade automatically - // the moment the vote passes. - - System::::can_set_code(origin, &validation_function)?; - ensure!(!PendingValidationFunction::exists(), Error::::OverlappingUpgrades); - let vfp = Self::validation_function_params().ok_or(Error::::ValidationFunctionParamsNotAvailable)?; - ensure!(validation_function.len() <= vfp.max_code_size as usize, Error::::TooBig); - let apply_block = vfp.code_upgrade_allowed.ok_or(Error::::ProhibitedByPolkadot)?; + Self::schedule_upgrade_impl(validation_function)?; + } - // When a code upgrade is scheduled, it has to be applied in two - // places, synchronized: both polkadot and the individual parachain - // have to upgrade on the same relay chain block. - // - // `notify_polkadot_of_pending_upgrade` notifies polkadot; the `PendingValidationFunction` - // storage keeps track locally for the parachain upgrade, which will - // be applied later. - Self::notify_polkadot_of_pending_upgrade(&validation_function); - PendingValidationFunction::put((apply_block, validation_function)); - Self::deposit_event(Event::ValidationFunctionStored(apply_block)); + /// Schedule a validation function upgrade without further checks. + /// + /// Same as [`Module::schedule_upgrade`], but without checking that the new `validation_function` + /// is correct. This makes it more flexible, but also opens the door to easily brick the chain. + #[weight = (0, DispatchClass::Operational)] + pub fn schedule_upgrade_without_checks(origin, validation_function: Vec) { + ensure_root(origin)?; + Self::schedule_upgrade_impl(validation_function)?; } /// Set the current validation function parameters @@ -114,8 +102,6 @@ decl_module! { /// /// As a side effect, this function upgrades the current validation function /// if the appropriate time has come. - // - // weight data just stolen from Timestamp::set; may be inappropriate #[weight = (0, DispatchClass::Mandatory)] fn set_validation_function_parameters(origin, vfp: ValidationFunctionParams) { ensure_none(origin)?; @@ -182,6 +168,27 @@ impl Module { pub fn max_code_size() -> Option { Self::validation_function_params().map(|vfp| vfp.max_code_size) } + + /// The implementation of the runtime upgrade scheduling. + fn schedule_upgrade_impl(validation_function: Vec) -> frame_support::dispatch::DispatchResult { + ensure!(!PendingValidationFunction::exists(), Error::::OverlappingUpgrades); + let vfp = Self::validation_function_params().ok_or(Error::::ValidationFunctionParamsNotAvailable)?; + ensure!(validation_function.len() <= vfp.max_code_size as usize, Error::::TooBig); + let apply_block = vfp.code_upgrade_allowed.ok_or(Error::::ProhibitedByPolkadot)?; + + // When a code upgrade is scheduled, it has to be applied in two + // places, synchronized: both polkadot and the individual parachain + // have to upgrade on the same relay chain block. + // + // `notify_polkadot_of_pending_upgrade` notifies polkadot; the `PendingValidationFunction` + // storage keeps track locally for the parachain upgrade, which will + // be applied later. + Self::notify_polkadot_of_pending_upgrade(&validation_function); + PendingValidationFunction::put((apply_block, validation_function)); + Self::deposit_event(Event::ValidationFunctionStored(apply_block)); + + Ok(()) + } } impl ProvideInherent for Module { diff --git a/rococo-parachains/contracts-runtime/src/lib.rs b/rococo-parachains/contracts-runtime/src/lib.rs index fd6c774bc7..fb530f7c20 100644 --- a/rococo-parachains/contracts-runtime/src/lib.rs +++ b/rococo-parachains/contracts-runtime/src/lib.rs @@ -61,7 +61,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("cumulus-contracts-parachain"), impl_name: create_runtime_str!("cumulus-contracts-parachain"), authoring_version: 1, - spec_version: 2, + spec_version: 4, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/rococo-parachains/runtime/src/lib.rs b/rococo-parachains/runtime/src/lib.rs index 072a2d048c..82af1ec314 100644 --- a/rococo-parachains/runtime/src/lib.rs +++ b/rococo-parachains/runtime/src/lib.rs @@ -63,7 +63,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("cumulus-test-parachain"), impl_name: create_runtime_str!("cumulus-test-parachain"), authoring_version: 1, - spec_version: 2, + spec_version: 3, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,