// Copyright 2022 Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus 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. // Cumulus 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 Cumulus. If not, see . #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; use cumulus_pallet_parachain_system as parachain_system; use frame_support::{dispatch::DispatchResult, pallet_prelude::*, weights::DispatchInfo}; use frame_system::pallet_prelude::*; pub use pallet::*; use polkadot_primitives::v2::PersistedValidationData; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, SignedExtension}, transaction_validity::{ InvalidTransaction, TransactionLongevity, TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, }, }; use sp_std::{prelude::*, vec::Vec}; #[frame_support::pallet] pub mod pallet { use super::*; #[pallet::config] pub trait Config: frame_system::Config + parachain_system::Config + pallet_sudo::Config { type Event: From + IsType<::Event>; } #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] pub struct Pallet(_); /// In case of a scheduled migration, this storage field contains the custom head data to be applied. #[pallet::storage] pub(super) type PendingCustomValidationHeadData = StorageValue<_, Vec, OptionQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// The custom validation head data has been scheduled to apply. CustomValidationHeadDataStored, /// The custom validation head data was applied as of the contained relay chain block number. CustomValidationHeadDataApplied, } #[pallet::error] pub enum Error { /// CustomHeadData is not stored in storage. NoCustomHeadData, } #[pallet::call] impl Pallet { #[pallet::weight(0)] pub fn schedule_migration( origin: OriginFor, code: Vec, head_data: Vec, ) -> DispatchResult { ensure_root(origin)?; parachain_system::Pallet::::schedule_code_upgrade(code)?; Self::store_pending_custom_validation_head_data(head_data); Ok(()) } } impl Pallet { /// Set a custom head data that should only be applied when upgradeGoAheadSignal from /// the Relay Chain is GoAhead fn store_pending_custom_validation_head_data(head_data: Vec) { PendingCustomValidationHeadData::::put(head_data); Self::deposit_event(Event::CustomValidationHeadDataStored); } /// Set pending custom head data as head data that will be returned by `validate_block`. on the relay chain. fn set_pending_custom_validation_head_data() { if let Some(head_data) = >::take() { parachain_system::Pallet::::set_custom_validation_head_data(head_data); Self::deposit_event(Event::CustomValidationHeadDataApplied); } } } impl parachain_system::OnSystemEvent for Pallet { fn on_validation_data(_data: &PersistedValidationData) {} fn on_validation_code_applied() { crate::Pallet::::set_pending_custom_validation_head_data(); } } /// Ensure that signed transactions are only valid if they are signed by root. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo, Default)] #[scale_info(skip_type_params(T))] pub struct CheckSudo(sp_std::marker::PhantomData); impl CheckSudo { pub fn new() -> Self { Self(Default::default()) } } impl sp_std::fmt::Debug for CheckSudo { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { write!(f, "CheckSudo") } #[cfg(not(feature = "std"))] fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { Ok(()) } } impl SignedExtension for CheckSudo where ::Call: Dispatchable, { type AccountId = T::AccountId; type Call = ::Call; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckSudo"; fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } fn pre_dispatch( self, who: &Self::AccountId, call: &Self::Call, info: &DispatchInfoOf, len: usize, ) -> Result { Ok(self.validate(who, call, info, len).map(|_| ())?) } fn validate( &self, who: &Self::AccountId, _call: &Self::Call, info: &DispatchInfoOf, _len: usize, ) -> TransactionValidity { let root_account = match pallet_sudo::Pallet::::key() { Some(account) => account, None => return Err(InvalidTransaction::BadSigner.into()), }; if *who == root_account { Ok(ValidTransaction { priority: info.weight as TransactionPriority, longevity: TransactionLongevity::max_value(), propagate: true, ..Default::default() }) } else { Err(InvalidTransaction::BadSigner.into()) } } } }