--- a/Cargo.lock +++ b/Cargo.lock @@ -5374,6 +5374,7 @@ "pallet-foreign-assets", "pallet-fungible", "pallet-inflation", + "pallet-maintenance", "pallet-nonfungible", "pallet-randomness-collective-flip", "pallet-refungible", @@ -6250,6 +6251,18 @@ ] [[package]] +name = "pallet-maintenance" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec 3.2.1", + "scale-info", + "sp-std", +] + +[[package]] name = "pallet-membership" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" @@ -8834,6 +8847,7 @@ "pallet-foreign-assets", "pallet-fungible", "pallet-inflation", + "pallet-maintenance", "pallet-nonfungible", "pallet-randomness-collective-flip", "pallet-refungible", @@ -12964,6 +12978,7 @@ "pallet-foreign-assets", "pallet-fungible", "pallet-inflation", + "pallet-maintenance", "pallet-nonfungible", "pallet-randomness-collective-flip", "pallet-refungible", --- /dev/null +++ b/pallets/maintenance/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "pallet-maintenance" +version = "0.1.0" +authors = ["Unique Network "] +edition = "2021" +license = "GPLv3" +homepage = "https://unique.network" +repository = "https://github.com/UniqueNetwork/unique-chain" +description = "Unique Maintenance pallet" +readme = "README.md" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] --- /dev/null +++ b/pallets/maintenance/src/benchmarking.rs @@ -0,0 +1,37 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +use super::*; +use crate::{Pallet as Maintenance, Config}; + +use frame_benchmarking::benchmarks; +use frame_system::RawOrigin; +use frame_support::ensure; + +benchmarks! { + enable { + }: _(RawOrigin::Root) + verify { + ensure!(>::get(), "didn't enable the MM"); + } + + disable { + Maintenance::::enable(RawOrigin::Root.into())?; + }: _(RawOrigin::Root) + verify { + ensure!(!>::get(), "didn't disable the MM"); + } +} --- /dev/null +++ b/pallets/maintenance/src/lib.rs @@ -0,0 +1,80 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +pub mod weights; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use crate::weights::WeightInfo; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + MaintenanceEnabled, + MaintenanceDisabled, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn is_enabled)] + pub type Enabled = StorageValue<_, bool, ValueQuery>; + + #[pallet::error] + pub enum Error {} + + #[pallet::call] + impl Pallet { + #[pallet::weight(::WeightInfo::enable())] + pub fn enable(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + + >::set(true); + + Self::deposit_event(Event::MaintenanceEnabled); + + Ok(()) + } + + #[pallet::weight(::WeightInfo::disable())] + pub fn disable(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + + >::set(false); + + Self::deposit_event(Event::MaintenanceDisabled); + + Ok(()) + } + } +} --- /dev/null +++ b/pallets/maintenance/src/weights.rs @@ -0,0 +1,67 @@ +// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs + +//! Autogenerated weights for pallet_maintenance +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-11-01, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// target/release/unique-collator +// benchmark +// pallet +// --pallet +// pallet-maintenance +// --wasm-execution +// compiled +// --extrinsic +// * +// --template +// .maintain/frame-weight-template.hbs +// --steps=50 +// --repeat=80 +// --heap-pages=4096 +// --output=./pallets/maintenance/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_maintenance. +pub trait WeightInfo { + fn enable() -> Weight; + fn disable() -> Weight; +} + +/// Weights for pallet_maintenance using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Maintenance Enabled (r:0 w:1) + fn enable() -> Weight { + Weight::from_ref_time(7_367_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Maintenance Enabled (r:0 w:1) + fn disable() -> Weight { + Weight::from_ref_time(7_273_000) + .saturating_add(T::DbWeight::get().writes(1)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Maintenance Enabled (r:0 w:1) + fn enable() -> Weight { + Weight::from_ref_time(7_367_000) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Maintenance Enabled (r:0 w:1) + fn disable() -> Weight { + Weight::from_ref_time(7_273_000) + .saturating_add(RocksDbWeight::get().writes(1)) + } +} --- a/runtime/common/config/pallets/mod.rs +++ b/runtime/common/config/pallets/mod.rs @@ -103,3 +103,8 @@ type DefaultWeightToFeeCoefficient = ConstU32<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>; type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>; } + +impl pallet_maintenance::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_maintenance::weights::SubstrateWeight; +} --- a/runtime/common/construct_runtime/mod.rs +++ b/runtime/common/construct_runtime/mod.rs @@ -94,6 +94,8 @@ EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152, EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153, + Maintenance: pallet_maintenance::{Pallet, Call, Storage, Event} = 154, + #[runtimes(opal)] TestUtils: pallet_test_utils = 255, } --- /dev/null +++ b/runtime/common/maintenance.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +use scale_info::TypeInfo; +use codec::{Encode, Decode}; +use up_common::types::AccountId; +use crate::{RuntimeCall, Maintenance}; + +use sp_runtime::{ + traits::{DispatchInfoOf, SignedExtension}, + transaction_validity::{ + TransactionValidity, ValidTransaction, InvalidTransaction, TransactionValidityError, + }, +}; + +#[derive(Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] +pub struct CheckMaintenance; + +impl SignedExtension for CheckMaintenance { + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + + const IDENTIFIER: &'static str = "CheckMaintenance"; + + fn additional_signed(&self) -> Result { + Ok(()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } + + fn validate( + &self, + _who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + if Maintenance::is_enabled() { + match call { + RuntimeCall::EvmMigration(_) + | RuntimeCall::EVM(_) + | RuntimeCall::Ethereum(_) + | RuntimeCall::Inflation(_) + | RuntimeCall::Maintenance(_) + | RuntimeCall::Structure(_) + | RuntimeCall::Unique(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + + #[cfg(feature = "scheduler")] + RuntimeCall::Scheduler(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + + #[cfg(feature = "rmrk")] + RuntimeCall::RmrkCore(_) | RuntimeCall::RmrkEquip(_) => { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + + #[cfg(feature = "app-promotion")] + RuntimeCall::AppPromotion(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + + #[cfg(feature = "foreign-assets")] + RuntimeCall::ForeignAssets(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + + #[cfg(feature = "pallet-test-utils")] + RuntimeCall::TestUtils(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + + _ => Ok(ValidTransaction::default()), + } + } else { + Ok(ValidTransaction::default()) + } + } + + fn pre_dispatch_unsigned( + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + Self::validate_unsigned(call, info, len).map(|_| ()) + } + + fn validate_unsigned( + call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + if Maintenance::is_enabled() { + match call { + RuntimeCall::EVM(_) | RuntimeCall::Ethereum(_) | RuntimeCall::EvmMigration(_) => { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + _ => Ok(ValidTransaction::default()), + } + } else { + Ok(ValidTransaction::default()) + } + } +} --- a/runtime/common/mod.rs +++ b/runtime/common/mod.rs @@ -20,6 +20,7 @@ pub mod ethereum; pub mod instance; pub mod runtime_apis; +pub mod maintenance; #[cfg(feature = "scheduler")] pub mod scheduler; @@ -90,6 +91,7 @@ frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, + maintenance::CheckMaintenance, ChargeTransactionPayment, //pallet_contract_helpers::ContractHelpersExtension, pallet_ethereum::FakeTransactionFinalizer, --- a/runtime/common/scheduler.rs +++ b/runtime/common/scheduler.rs @@ -25,7 +25,7 @@ DispatchErrorWithPostInfo, DispatchError, }; use codec::Encode; -use crate::{Runtime, RuntimeCall, RuntimeOrigin, Balances}; +use crate::{Runtime, RuntimeCall, RuntimeOrigin, Balances, maintenance}; use up_common::types::{AccountId, Balance}; use fp_self_contained::SelfContainedCall; use pallet_unique_scheduler::DispatchCall; @@ -41,6 +41,7 @@ frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, + maintenance::CheckMaintenance, ChargeTransactionPayment, ); @@ -53,6 +54,7 @@ from, )), frame_system::CheckWeight::::new(), + maintenance::CheckMaintenance, ChargeTransactionPayment::::from(0), ) } --- a/runtime/opal/Cargo.toml +++ b/runtime/opal/Cargo.toml @@ -45,6 +45,7 @@ 'pallet-xcm/runtime-benchmarks', 'sp-runtime/runtime-benchmarks', 'xcm-builder/runtime-benchmarks', + 'pallet-maintenance/runtime-benchmarks', ] try-runtime = [ 'frame-try-runtime', @@ -88,6 +89,7 @@ 'pallet-evm-contract-helpers/try-runtime', 'pallet-evm-transaction-payment/try-runtime', 'pallet-evm-migration/try-runtime', + 'pallet-maintenance/try-runtime', 'pallet-test-utils?/try-runtime', ] std = [ @@ -169,6 +171,7 @@ "orml-traits/std", "pallet-foreign-assets/std", + 'pallet-maintenance/std', 'pallet-test-utils?/std', ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] @@ -485,6 +488,7 @@ evm-coder = { default-features = false, path = '../../crates/evm-coder' } up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' } pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" } +pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" } ################################################################################ # Test dependencies --- a/runtime/quartz/Cargo.toml +++ b/runtime/quartz/Cargo.toml @@ -44,6 +44,7 @@ 'pallet-xcm/runtime-benchmarks', 'sp-runtime/runtime-benchmarks', 'xcm-builder/runtime-benchmarks', + 'pallet-maintenance/runtime-benchmarks', ] try-runtime = [ 'frame-try-runtime', @@ -87,6 +88,7 @@ 'pallet-evm-contract-helpers/try-runtime', 'pallet-evm-transaction-payment/try-runtime', 'pallet-evm-migration/try-runtime', + 'pallet-maintenance/try-runtime', ] std = [ 'codec/std', @@ -165,6 +167,7 @@ "orml-xtokens/std", "orml-traits/std", "pallet-foreign-assets/std", + "pallet-maintenance/std", ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] quartz-runtime = ['refungible'] @@ -487,6 +490,7 @@ evm-coder = { default-features = false, path = '../../crates/evm-coder' } up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' } pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" } +pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" } ################################################################################ # Other Dependencies --- a/runtime/unique/Cargo.toml +++ b/runtime/unique/Cargo.toml @@ -45,6 +45,7 @@ 'sp-runtime/runtime-benchmarks', 'xcm-builder/runtime-benchmarks', 'up-data-structs/runtime-benchmarks', + 'pallet-maintenance/runtime-benchmarks', ] try-runtime = [ 'frame-try-runtime', @@ -88,6 +89,7 @@ 'pallet-evm-contract-helpers/try-runtime', 'pallet-evm-transaction-payment/try-runtime', 'pallet-evm-migration/try-runtime', + 'pallet-maintenance/try-runtime', ] std = [ 'codec/std', @@ -166,6 +168,7 @@ "orml-xtokens/std", "orml-traits/std", "pallet-foreign-assets/std", + "pallet-maintenance/std", ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] unique-runtime = [] @@ -482,6 +485,7 @@ evm-coder = { default-features = false, path = '../../crates/evm-coder' } up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' } pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" } +pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" } ################################################################################ # Other Dependencies --- a/tests/src/pallet-presence.test.ts +++ b/tests/src/pallet-presence.test.ts @@ -47,6 +47,7 @@ 'configuration', 'tokens', 'xtokens', + 'maintenance', ]; // Pallets that depend on consensus and governance configuration