// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Pezcumulus. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Module contains predefined test-case scenarios for `Runtime` with common functionality. use crate::{ AccountIdOf, BasicTeyrchainRuntime, CollatorSessionKeys, ExtBuilder, GovernanceOrigin, RuntimeCallOf, RuntimeOriginOf, ValidatorIdOf, }; use codec::Encode; use pezframe_support::{ assert_ok, traits::{Get, OriginTrait}, weights::WeightToFee as WeightToFeeT, }; use pezsp_runtime::{ traits::{Block as BlockT, SaturatedConversion, StaticLookup}, DispatchError, Either, }; use teyrchains_common::AccountId; use xcm::prelude::InstructionError; use xcm_runtime_apis::fees::{ runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, Error as XcmPaymentApiError, }; type RuntimeHelper = crate::RuntimeHelper; /// Test-case makes sure that `Runtime` can change storage constant via governance-like call pub fn change_storage_constant_by_governance_works( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, governance_origin: GovernanceOrigin>, storage_constant_key_value: fn() -> (Vec, StorageConstantType), new_storage_constant_value: fn(&StorageConstantType) -> StorageConstantType, ) where Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config + pezpallet_xcm::Config + teyrchain_info::Config + pezpallet_collator_selection::Config + cumulus_pallet_teyrchain_system::Config + pezpallet_timestamp::Config, ValidatorIdOf: From>, StorageConstant: Get, StorageConstantType: Encode + PartialEq + std::fmt::Debug, { ExtBuilder::::default() .with_collators(collator_session_key.collators()) .with_session_keys(collator_session_key.session_keys()) .with_para_id(runtime_para_id.into()) .with_tracing() .build() .execute_with(|| { let (storage_constant_key, storage_constant_init_value): ( Vec, StorageConstantType, ) = storage_constant_key_value(); // check delivery reward constant before (not stored yet, just as default value is used) assert_eq!(StorageConstant::get(), storage_constant_init_value); assert_eq!(pezsp_io::storage::get(&storage_constant_key), None); let new_storage_constant_value = new_storage_constant_value(&storage_constant_init_value); assert_ne!(new_storage_constant_value, storage_constant_init_value); // encode `set_storage` call let set_storage_call = RuntimeCallOf::::from(pezframe_system::Call::::set_storage { items: vec![( storage_constant_key.clone(), new_storage_constant_value.encode(), )], }); // execute XCM with Transact to `set_storage` as governance does assert_ok!(RuntimeHelper::::execute_as_governance_call( set_storage_call, governance_origin )); // check delivery reward constant after (stored) assert_eq!(StorageConstant::get(), new_storage_constant_value); assert_eq!( pezsp_io::storage::get(&storage_constant_key), Some(new_storage_constant_value.encode().into()) ); }) } /// Test-case makes sure that `Runtime` can change storage constant via governance-like call pub fn set_storage_keys_by_governance_works( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, governance_origin: GovernanceOrigin>, storage_items: Vec<(Vec, Vec)>, initialize_storage: impl FnOnce() -> (), assert_storage: impl FnOnce() -> (), ) where Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config + pezpallet_xcm::Config + teyrchain_info::Config + pezpallet_collator_selection::Config + cumulus_pallet_teyrchain_system::Config + pezpallet_timestamp::Config, ValidatorIdOf: From>, { let mut runtime = ExtBuilder::::default() .with_collators(collator_session_key.collators()) .with_session_keys(collator_session_key.session_keys()) .with_para_id(runtime_para_id.into()) .with_tracing() .build(); runtime.execute_with(|| { initialize_storage(); }); runtime.execute_with(|| { // encode `kill_storage` call let kill_storage_call = RuntimeCallOf::::from(pezframe_system::Call::::set_storage { items: storage_items.clone(), }); // execute XCM with Transact to `set_storage` as governance does assert_ok!(RuntimeHelper::::execute_as_governance_call( kill_storage_call, governance_origin )); }); runtime.execute_with(|| { assert_storage(); }); } pub fn xcm_payment_api_with_native_token_works< Runtime, RuntimeCall, RuntimeOrigin, Block, WeightToFee, >() where Runtime: XcmPaymentApiV2 + pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config + pezpallet_xcm::Config + teyrchain_info::Config + pezpallet_collator_selection::Config + cumulus_pallet_teyrchain_system::Config + cumulus_pallet_xcmp_queue::Config + pezpallet_timestamp::Config, ValidatorIdOf: From>, RuntimeOrigin: OriginTrait::AccountId>, <::Lookup as StaticLookup>::Source: From<::AccountId>, Block: BlockT, WeightToFee: WeightToFeeT, { use xcm::prelude::*; ExtBuilder::::default().build().execute_with(|| { let transfer_amount = 100u128; let xcm_to_weigh = Xcm::::builder_unsafe() .withdraw_asset((Here, transfer_amount)) .buy_execution((Here, transfer_amount), Unlimited) .deposit_asset(AllCounted(1), [1u8; 32]) .build(); let versioned_xcm_to_weigh = VersionedXcm::from(xcm_to_weigh.clone().into()); // We first try calling it with a lower XCM version. let lower_version_xcm_to_weigh = versioned_xcm_to_weigh.clone().into_version(XCM_VERSION - 1).unwrap(); let xcm_weight = Runtime::query_xcm_weight(lower_version_xcm_to_weigh) .expect("xcm weight must be computed"); let expected_weight_fee: u128 = WeightToFee::weight_to_fee(&xcm_weight).saturated_into(); let native_token: Location = Parent.into(); let native_token_versioned = VersionedAssetId::from(AssetId(native_token)); let lower_version_native_token = native_token_versioned.clone().into_version(XCM_VERSION - 1).unwrap(); let execution_fees = Runtime::query_weight_to_asset_fee(xcm_weight, lower_version_native_token) .expect("weight must be converted to native fee"); assert_eq!(execution_fees, expected_weight_fee); // Now we call it with the latest version. let xcm_weight = Runtime::query_xcm_weight(versioned_xcm_to_weigh).expect("xcm weight must be computed"); let expected_weight_fee: u128 = WeightToFee::weight_to_fee(&xcm_weight).saturated_into(); let execution_fees = Runtime::query_weight_to_asset_fee(xcm_weight, native_token_versioned) .expect("weight must be converted to native fee"); assert_eq!(execution_fees, expected_weight_fee); // If we call it with anything other than the native token it will error. let non_existent_token: Location = Here.into(); let non_existent_token_versioned = VersionedAssetId::from(AssetId(non_existent_token)); let execution_fees = Runtime::query_weight_to_asset_fee(xcm_weight, non_existent_token_versioned); assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound)); }); } /// Generic test case for Pezcumulus-based teyrchain that verifies if runtime can process /// `pezframe_system::Call::authorize_upgrade` from governance system. pub fn can_governance_authorize_upgrade( governance_origin: GovernanceOrigin, ) -> Result<(), Either> where Runtime: BasicTeyrchainRuntime + pezframe_system::Config, { ExtBuilder::::default().build().execute_with(|| { // check before assert!(pezframe_system::Pallet::::authorized_upgrade().is_none()); // execute call as governance does let code_hash = Runtime::Hash::default(); let authorize_upgrade_call: ::RuntimeCall = pezframe_system::Call::::authorize_upgrade { code_hash }.into(); RuntimeHelper::::execute_as_governance_call( authorize_upgrade_call, governance_origin, )?; // check after match pezframe_system::Pallet::::authorized_upgrade() { None => Err(Either::Left(pezframe_system::Error::::NothingAuthorized.into())), Some(_) => Ok(()), } }) }