feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,766 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// 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.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use codec::{Decode, DecodeLimit};
|
||||
use cumulus_pallet_teyrchain_system::teyrchain_inherent::{
|
||||
deconstruct_teyrchain_inherent_data, InboundMessagesData,
|
||||
};
|
||||
use cumulus_primitives_core::{
|
||||
relay_chain::Slot, AbridgedHrmpChannel, ParaId, PersistedValidationData,
|
||||
};
|
||||
use cumulus_primitives_teyrchain_inherent::TeyrchainInherentData;
|
||||
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
|
||||
use pezframe_support::{
|
||||
dispatch::{DispatchResult, GetDispatchInfo, RawOrigin},
|
||||
inherent::{InherentData, ProvideInherent},
|
||||
pezpallet_prelude::Get,
|
||||
traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable},
|
||||
weights::Weight,
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::{BlockNumberFor, HeaderFor};
|
||||
use pezkuwi_teyrchain_primitives::primitives::{
|
||||
HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat,
|
||||
};
|
||||
use pezsp_consensus_aura::{SlotDuration, AURA_ENGINE_ID};
|
||||
use pezsp_core::{Encode, U256};
|
||||
use pezsp_runtime::{
|
||||
traits::{Dispatchable, Header},
|
||||
BuildStorage, Digest, DigestItem, DispatchError, Either, SaturatedConversion,
|
||||
};
|
||||
use xcm::{
|
||||
latest::{Asset, Location, XcmContext, XcmHash},
|
||||
prelude::*,
|
||||
VersionedXcm, MAX_XCM_DECODE_DEPTH,
|
||||
};
|
||||
use xcm_executor::{traits::TransactAsset, AssetsInHolding};
|
||||
|
||||
pub mod test_cases;
|
||||
|
||||
pub type BalanceOf<Runtime> = <Runtime as pezpallet_balances::Config>::Balance;
|
||||
pub type AccountIdOf<Runtime> = <Runtime as pezframe_system::Config>::AccountId;
|
||||
pub type RuntimeCallOf<Runtime> = <Runtime as pezframe_system::Config>::RuntimeCall;
|
||||
pub type RuntimeOriginOf<Runtime> = <Runtime as pezframe_system::Config>::RuntimeOrigin;
|
||||
pub type ValidatorIdOf<Runtime> = <Runtime as pezpallet_session::Config>::ValidatorId;
|
||||
pub type SessionKeysOf<Runtime> = <Runtime as pezpallet_session::Config>::Keys;
|
||||
|
||||
pub struct CollatorSessionKey<
|
||||
Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config,
|
||||
> {
|
||||
collator: AccountIdOf<Runtime>,
|
||||
validator: ValidatorIdOf<Runtime>,
|
||||
key: SessionKeysOf<Runtime>,
|
||||
}
|
||||
|
||||
pub struct CollatorSessionKeys<
|
||||
Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config,
|
||||
> {
|
||||
items: Vec<CollatorSessionKey<Runtime>>,
|
||||
}
|
||||
|
||||
impl<Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config>
|
||||
CollatorSessionKey<Runtime>
|
||||
{
|
||||
pub fn new(
|
||||
collator: AccountIdOf<Runtime>,
|
||||
validator: ValidatorIdOf<Runtime>,
|
||||
key: SessionKeysOf<Runtime>,
|
||||
) -> Self {
|
||||
Self { collator, validator, key }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config> Default
|
||||
for CollatorSessionKeys<Runtime>
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self { items: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: pezframe_system::Config + pezpallet_balances::Config + pezpallet_session::Config>
|
||||
CollatorSessionKeys<Runtime>
|
||||
{
|
||||
pub fn new(
|
||||
collator: AccountIdOf<Runtime>,
|
||||
validator: ValidatorIdOf<Runtime>,
|
||||
key: SessionKeysOf<Runtime>,
|
||||
) -> Self {
|
||||
Self { items: vec![CollatorSessionKey::new(collator, validator, key)] }
|
||||
}
|
||||
|
||||
pub fn add(mut self, item: CollatorSessionKey<Runtime>) -> Self {
|
||||
self.items.push(item);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn collators(&self) -> Vec<AccountIdOf<Runtime>> {
|
||||
self.items.iter().map(|item| item.collator.clone()).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn session_keys(
|
||||
&self,
|
||||
) -> Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)> {
|
||||
self.items
|
||||
.iter()
|
||||
.map(|item| (item.collator.clone(), item.validator.clone(), item.key.clone()))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SlotDurations {
|
||||
pub relay: SlotDuration,
|
||||
pub para: SlotDuration,
|
||||
}
|
||||
|
||||
/// A set of traits for a minimal teyrchain runtime, that may be used in conjunction with the
|
||||
/// `ExtBuilder` and the `RuntimeHelper`.
|
||||
pub trait BasicTeyrchainRuntime:
|
||||
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
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> BasicTeyrchainRuntime for T
|
||||
where
|
||||
T: 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<T>: From<AccountIdOf<T>>,
|
||||
{
|
||||
}
|
||||
|
||||
/// Basic builder based on balances, collators and pezpallet_session.
|
||||
pub struct ExtBuilder<Runtime: BasicTeyrchainRuntime> {
|
||||
// endowed accounts with balances
|
||||
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
||||
// collators to test block prod
|
||||
collators: Vec<AccountIdOf<Runtime>>,
|
||||
// keys added to pallet session
|
||||
keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
|
||||
// safe XCM version for pezpallet_xcm
|
||||
safe_xcm_version: Option<XcmVersion>,
|
||||
// para id
|
||||
para_id: Option<ParaId>,
|
||||
_runtime: PhantomData<Runtime>,
|
||||
}
|
||||
|
||||
impl<Runtime: BasicTeyrchainRuntime> Default for ExtBuilder<Runtime> {
|
||||
fn default() -> ExtBuilder<Runtime> {
|
||||
ExtBuilder {
|
||||
balances: vec![],
|
||||
collators: vec![],
|
||||
keys: vec![],
|
||||
safe_xcm_version: None,
|
||||
para_id: None,
|
||||
_runtime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: BasicTeyrchainRuntime> ExtBuilder<Runtime> {
|
||||
pub fn with_balances(
|
||||
mut self,
|
||||
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
||||
) -> Self {
|
||||
self.balances = balances;
|
||||
self
|
||||
}
|
||||
pub fn with_collators(mut self, collators: Vec<AccountIdOf<Runtime>>) -> Self {
|
||||
self.collators = collators;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_session_keys(
|
||||
mut self,
|
||||
keys: Vec<(AccountIdOf<Runtime>, ValidatorIdOf<Runtime>, SessionKeysOf<Runtime>)>,
|
||||
) -> Self {
|
||||
self.keys = keys;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_tracing(self) -> Self {
|
||||
pezsp_tracing::try_init_simple();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_safe_xcm_version(mut self, safe_xcm_version: XcmVersion) -> Self {
|
||||
self.safe_xcm_version = Some(safe_xcm_version);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_para_id(mut self, para_id: ParaId) -> Self {
|
||||
self.para_id = Some(para_id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> pezsp_io::TestExternalities {
|
||||
let mut t = pezframe_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
|
||||
|
||||
pezpallet_xcm::GenesisConfig::<Runtime> {
|
||||
safe_xcm_version: self.safe_xcm_version,
|
||||
..Default::default()
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
if let Some(para_id) = self.para_id {
|
||||
teyrchain_info::GenesisConfig::<Runtime> {
|
||||
teyrchain_id: para_id,
|
||||
..Default::default()
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pezpallet_balances::GenesisConfig::<Runtime> { balances: self.balances, ..Default::default() }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
pezpallet_collator_selection::GenesisConfig::<Runtime> {
|
||||
invulnerables: self.collators.clone(),
|
||||
candidacy_bond: Default::default(),
|
||||
desired_candidates: Default::default(),
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
pezpallet_session::GenesisConfig::<Runtime> { keys: self.keys, ..Default::default() }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = pezsp_io::TestExternalities::new(t);
|
||||
|
||||
ext.execute_with(|| {
|
||||
pezframe_system::Pallet::<Runtime>::set_block_number(1u32.into());
|
||||
});
|
||||
|
||||
ext
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RuntimeHelper<Runtime, AllPalletsWithoutSystem>(
|
||||
PhantomData<(Runtime, AllPalletsWithoutSystem)>,
|
||||
);
|
||||
/// Utility function that advances the chain to the desired block number.
|
||||
/// If an author is provided, that author information is injected to all the blocks in the meantime.
|
||||
impl<
|
||||
Runtime: pezframe_system::Config + cumulus_pallet_teyrchain_system::Config + pezpallet_timestamp::Config,
|
||||
AllPalletsWithoutSystem,
|
||||
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
|
||||
where
|
||||
AccountIdOf<Runtime>:
|
||||
Into<<<Runtime as pezframe_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
|
||||
AllPalletsWithoutSystem:
|
||||
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||
{
|
||||
pub fn run_to_block(n: u32, author: AccountIdOf<Runtime>) -> HeaderFor<Runtime> {
|
||||
let mut last_header = None;
|
||||
loop {
|
||||
let block_number = pezframe_system::Pallet::<Runtime>::block_number();
|
||||
if block_number >= n.into() {
|
||||
break;
|
||||
}
|
||||
// Set the new block number and author
|
||||
|
||||
// Inherent is not created at every block, don't finalize teyrchain
|
||||
// system to avoid panicking.
|
||||
let header = pezframe_system::Pallet::<Runtime>::finalize();
|
||||
|
||||
let pre_digest =
|
||||
Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, author.encode())] };
|
||||
pezframe_system::Pallet::<Runtime>::reset_events();
|
||||
|
||||
let next_block_number = block_number + 1u32.into();
|
||||
pezframe_system::Pallet::<Runtime>::initialize(
|
||||
&next_block_number,
|
||||
&header.hash(),
|
||||
&pre_digest,
|
||||
);
|
||||
AllPalletsWithoutSystem::on_initialize(next_block_number);
|
||||
last_header = Some(header);
|
||||
}
|
||||
last_header.expect("run_to_block empty block range")
|
||||
}
|
||||
|
||||
pub fn run_to_block_with_finalize(n: u32) -> HeaderFor<Runtime> {
|
||||
let mut last_header = None;
|
||||
loop {
|
||||
let block_number = pezframe_system::Pallet::<Runtime>::block_number();
|
||||
if block_number >= n.into() {
|
||||
break;
|
||||
}
|
||||
// Set the new block number and author
|
||||
let header = pezframe_system::Pallet::<Runtime>::finalize();
|
||||
|
||||
let pre_digest = Digest {
|
||||
logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, block_number.encode())],
|
||||
};
|
||||
pezframe_system::Pallet::<Runtime>::reset_events();
|
||||
|
||||
let next_block_number = block_number + 1u32.into();
|
||||
pezframe_system::Pallet::<Runtime>::initialize(
|
||||
&next_block_number,
|
||||
&header.hash(),
|
||||
&pre_digest,
|
||||
);
|
||||
AllPalletsWithoutSystem::on_initialize(next_block_number);
|
||||
|
||||
let parent_head = HeadData(header.encode());
|
||||
let sproof_builder = RelayStateSproofBuilder {
|
||||
para_id: <Runtime>::SelfParaId::get(),
|
||||
included_para_head: parent_head.clone().into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let (relay_parent_storage_root, relay_chain_state) =
|
||||
sproof_builder.into_state_root_and_proof();
|
||||
let inherent_data = TeyrchainInherentData {
|
||||
validation_data: PersistedValidationData {
|
||||
parent_head,
|
||||
relay_parent_number: (block_number.saturated_into::<u32>() * 2 + 1).into(),
|
||||
relay_parent_storage_root,
|
||||
max_pov_size: 100_000_000,
|
||||
},
|
||||
relay_chain_state,
|
||||
downward_messages: Default::default(),
|
||||
horizontal_messages: Default::default(),
|
||||
relay_parent_descendants: Default::default(),
|
||||
collator_peer_id: None,
|
||||
};
|
||||
|
||||
let (inherent_data, downward_messages, horizontal_messages) =
|
||||
deconstruct_teyrchain_inherent_data(inherent_data);
|
||||
|
||||
let _ = cumulus_pallet_teyrchain_system::Pallet::<Runtime>::set_validation_data(
|
||||
Runtime::RuntimeOrigin::none(),
|
||||
inherent_data,
|
||||
InboundMessagesData::new(
|
||||
downward_messages.into_abridged(&mut usize::MAX.clone()),
|
||||
horizontal_messages.into_abridged(&mut usize::MAX.clone()),
|
||||
),
|
||||
);
|
||||
let _ = pezpallet_timestamp::Pallet::<Runtime>::set(
|
||||
Runtime::RuntimeOrigin::none(),
|
||||
300_u32.into(),
|
||||
);
|
||||
AllPalletsWithoutSystem::on_finalize(next_block_number);
|
||||
let header = pezframe_system::Pallet::<Runtime>::finalize();
|
||||
last_header = Some(header);
|
||||
}
|
||||
last_header.expect("run_to_block empty block range")
|
||||
}
|
||||
|
||||
pub fn root_origin() -> <Runtime as pezframe_system::Config>::RuntimeOrigin {
|
||||
<Runtime as pezframe_system::Config>::RuntimeOrigin::root()
|
||||
}
|
||||
|
||||
pub fn block_number() -> U256 {
|
||||
pezframe_system::Pallet::<Runtime>::block_number().into()
|
||||
}
|
||||
|
||||
pub fn origin_of(
|
||||
account_id: AccountIdOf<Runtime>,
|
||||
) -> <Runtime as pezframe_system::Config>::RuntimeOrigin {
|
||||
<Runtime as pezframe_system::Config>::RuntimeOrigin::signed(account_id.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<XcmConfig: xcm_executor::Config, AllPalletsWithoutSystem>
|
||||
RuntimeHelper<XcmConfig, AllPalletsWithoutSystem>
|
||||
{
|
||||
pub fn do_transfer(
|
||||
from: Location,
|
||||
to: Location,
|
||||
(asset, amount): (Location, u128),
|
||||
) -> Result<AssetsInHolding, XcmError> {
|
||||
<XcmConfig::AssetTransactor as TransactAsset>::transfer_asset(
|
||||
&Asset { id: AssetId(asset), fun: Fungible(amount) },
|
||||
&from,
|
||||
&to,
|
||||
// We aren't able to track the XCM that initiated the fee deposit, so we create a
|
||||
// fake message hash here
|
||||
&XcmContext::with_message_id([0; 32]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Runtime: pezpallet_xcm::Config + cumulus_pallet_teyrchain_system::Config,
|
||||
AllPalletsWithoutSystem,
|
||||
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
|
||||
{
|
||||
pub fn do_teleport_assets<HrmpChannelOpener>(
|
||||
origin: <Runtime as pezframe_system::Config>::RuntimeOrigin,
|
||||
dest: Location,
|
||||
beneficiary: Location,
|
||||
(asset, amount): (Location, u128),
|
||||
open_hrmp_channel: Option<(u32, u32)>,
|
||||
included_head: HeaderFor<Runtime>,
|
||||
slot_digest: &[u8],
|
||||
slot_durations: &SlotDurations,
|
||||
) -> DispatchResult
|
||||
where
|
||||
HrmpChannelOpener: pezframe_support::inherent::ProvideInherent<
|
||||
Call = cumulus_pallet_teyrchain_system::Call<Runtime>,
|
||||
>,
|
||||
{
|
||||
// open hrmp (if needed)
|
||||
if let Some((source_para_id, target_para_id)) = open_hrmp_channel {
|
||||
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
|
||||
source_para_id.into(),
|
||||
target_para_id.into(),
|
||||
included_head,
|
||||
slot_digest,
|
||||
slot_durations,
|
||||
);
|
||||
}
|
||||
|
||||
// do teleport
|
||||
<pezpallet_xcm::Pallet<Runtime>>::limited_teleport_assets(
|
||||
origin,
|
||||
Box::new(dest.into()),
|
||||
Box::new(beneficiary.into()),
|
||||
Box::new((AssetId(asset.clone()), amount).into()),
|
||||
Box::new(AssetId(asset).into()),
|
||||
Unlimited,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Runtime: cumulus_pallet_teyrchain_system::Config + pezpallet_xcm::Config,
|
||||
AllPalletsWithoutSystem,
|
||||
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
|
||||
{
|
||||
#[deprecated(
|
||||
note = "Will be removed after Aug 2025; It uses hard-coded `Location::parent()`, \
|
||||
use `execute_as_governance_call` instead."
|
||||
)]
|
||||
pub fn execute_as_governance(call: Vec<u8>) -> Outcome {
|
||||
// prepare xcm as governance will do
|
||||
let xcm = Xcm(vec![
|
||||
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||
Transact {
|
||||
origin_kind: OriginKind::Superuser,
|
||||
call: call.into(),
|
||||
fallback_max_weight: None,
|
||||
},
|
||||
ExpectTransactStatus(MaybeErrorCode::Success),
|
||||
]);
|
||||
|
||||
// execute xcm as parent origin
|
||||
let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
|
||||
<<Runtime as pezpallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
|
||||
Location::parent(),
|
||||
xcm,
|
||||
&mut hash,
|
||||
Self::xcm_max_weight(XcmReceivedFrom::Parent),
|
||||
Weight::zero(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn execute_as_governance_call<Call: Dispatchable + Encode>(
|
||||
call: Call,
|
||||
governance_origin: GovernanceOrigin<Call::RuntimeOrigin>,
|
||||
) -> Result<(), Either<DispatchError, InstructionError>> {
|
||||
// execute xcm as governance would send
|
||||
let execute_xcm = |call: Call, governance_location, descend_origin| {
|
||||
// prepare xcm
|
||||
let xcm = if let Some(descend_origin) = descend_origin {
|
||||
Xcm::builder_unsafe().descend_origin(descend_origin)
|
||||
} else {
|
||||
Xcm::builder_unsafe()
|
||||
}
|
||||
.unpaid_execution(Unlimited, None)
|
||||
.transact(OriginKind::Superuser, None, call.encode())
|
||||
.expect_transact_status(MaybeErrorCode::Success)
|
||||
.build();
|
||||
|
||||
let xcm_max_weight = Self::xcm_max_weight_for_location(&governance_location);
|
||||
let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
|
||||
|
||||
<<Runtime as pezpallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
|
||||
governance_location,
|
||||
xcm,
|
||||
&mut hash,
|
||||
xcm_max_weight,
|
||||
Weight::zero(),
|
||||
)
|
||||
};
|
||||
|
||||
match governance_origin {
|
||||
// we are simulating a case of receiving an XCM
|
||||
// and Location::Here() is not a valid destionation for XcmRouter in the fist place
|
||||
GovernanceOrigin::Location(location) if location == Location::here() => {
|
||||
panic!("Location::here() not supported, use GovernanceOrigin::Origin instead")
|
||||
},
|
||||
GovernanceOrigin::Location(location) =>
|
||||
execute_xcm(call, location, None).ensure_complete().map_err(Either::Right),
|
||||
GovernanceOrigin::LocationAndDescendOrigin(location, descend_origin) =>
|
||||
execute_xcm(call, location, Some(descend_origin))
|
||||
.ensure_complete()
|
||||
.map_err(Either::Right),
|
||||
GovernanceOrigin::Origin(origin) =>
|
||||
call.dispatch(origin).map(|_| ()).map_err(|e| Either::Left(e.error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute_as_origin<Call: GetDispatchInfo + Encode>(
|
||||
(origin, origin_kind): (Location, OriginKind),
|
||||
call: Call,
|
||||
maybe_buy_execution_fee: Option<Asset>,
|
||||
) -> Outcome {
|
||||
let mut instructions = if let Some(buy_execution_fee) = maybe_buy_execution_fee {
|
||||
vec![
|
||||
WithdrawAsset(buy_execution_fee.clone().into()),
|
||||
BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
|
||||
]
|
||||
} else {
|
||||
vec![UnpaidExecution { check_origin: None, weight_limit: Unlimited }]
|
||||
};
|
||||
|
||||
// prepare `Transact` xcm
|
||||
instructions.extend(vec![
|
||||
Transact { origin_kind, call: call.encode().into(), fallback_max_weight: None },
|
||||
ExpectTransactStatus(MaybeErrorCode::Success),
|
||||
]);
|
||||
let xcm = Xcm(instructions);
|
||||
let xcm_max_weight = Self::xcm_max_weight_for_location(&origin);
|
||||
|
||||
// execute xcm as parent origin
|
||||
let mut hash = xcm.using_encoded(pezsp_io::hashing::blake2_256);
|
||||
<<Runtime as pezpallet_xcm::Config>::XcmExecutor>::prepare_and_execute(
|
||||
origin,
|
||||
xcm,
|
||||
&mut hash,
|
||||
xcm_max_weight,
|
||||
Weight::zero(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum representing governance origin/location.
|
||||
#[derive(Clone)]
|
||||
pub enum GovernanceOrigin<RuntimeOrigin> {
|
||||
Location(Location),
|
||||
LocationAndDescendOrigin(Location, InteriorLocation),
|
||||
Origin(RuntimeOrigin),
|
||||
}
|
||||
|
||||
pub enum XcmReceivedFrom {
|
||||
Parent,
|
||||
Sibling,
|
||||
}
|
||||
|
||||
impl<TeyrchainSystem: cumulus_pallet_teyrchain_system::Config, AllPalletsWithoutSystem>
|
||||
RuntimeHelper<TeyrchainSystem, AllPalletsWithoutSystem>
|
||||
{
|
||||
pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
|
||||
match from {
|
||||
XcmReceivedFrom::Parent => TeyrchainSystem::ReservedDmpWeight::get(),
|
||||
XcmReceivedFrom::Sibling => TeyrchainSystem::ReservedXcmpWeight::get(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xcm_max_weight_for_location(location: &Location) -> Weight {
|
||||
Self::xcm_max_weight(if location == &Location::parent() {
|
||||
XcmReceivedFrom::Parent
|
||||
} else {
|
||||
XcmReceivedFrom::Sibling
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Runtime: pezframe_system::Config + pezpallet_xcm::Config, AllPalletsWithoutSystem>
|
||||
RuntimeHelper<Runtime, AllPalletsWithoutSystem>
|
||||
{
|
||||
pub fn assert_pallet_xcm_event_outcome(
|
||||
unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pezpallet_xcm::Event<Runtime>>>,
|
||||
assert_outcome: fn(Outcome),
|
||||
) {
|
||||
assert_outcome(Self::get_pallet_xcm_event_outcome(unwrap_pallet_xcm_event));
|
||||
}
|
||||
|
||||
pub fn get_pallet_xcm_event_outcome(
|
||||
unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pezpallet_xcm::Event<Runtime>>>,
|
||||
) -> Outcome {
|
||||
<pezframe_system::Pallet<Runtime>>::events()
|
||||
.into_iter()
|
||||
.filter_map(|e| unwrap_pallet_xcm_event(e.event.encode()))
|
||||
.find_map(|e| match e {
|
||||
pezpallet_xcm::Event::Attempted { outcome } => Some(outcome),
|
||||
_ => None,
|
||||
})
|
||||
.expect("No `pezpallet_xcm::Event::Attempted(outcome)` event found!")
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Runtime: pezframe_system::Config + cumulus_pallet_xcmp_queue::Config,
|
||||
AllPalletsWithoutSystem,
|
||||
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
|
||||
{
|
||||
pub fn xcmp_queue_message_sent(
|
||||
unwrap_xcmp_queue_event: Box<
|
||||
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
|
||||
>,
|
||||
) -> Option<XcmHash> {
|
||||
<pezframe_system::Pallet<Runtime>>::events()
|
||||
.into_iter()
|
||||
.filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
|
||||
.find_map(|e| match e {
|
||||
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } =>
|
||||
Some(message_hash),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_metadata<Fungibles, AccountId>(
|
||||
asset_id: impl Into<Fungibles::AssetId> + Clone,
|
||||
expected_name: &str,
|
||||
expected_symbol: &str,
|
||||
expected_decimals: u8,
|
||||
) where
|
||||
Fungibles: pezframe_support::traits::fungibles::metadata::Inspect<AccountId>
|
||||
+ pezframe_support::traits::fungibles::Inspect<AccountId>,
|
||||
{
|
||||
assert_eq!(Fungibles::name(asset_id.clone().into()), Vec::from(expected_name),);
|
||||
assert_eq!(Fungibles::symbol(asset_id.clone().into()), Vec::from(expected_symbol),);
|
||||
assert_eq!(Fungibles::decimals(asset_id.into()), expected_decimals);
|
||||
}
|
||||
|
||||
pub fn assert_total<Fungibles, AccountId>(
|
||||
asset_id: impl Into<Fungibles::AssetId> + Clone,
|
||||
expected_total_issuance: impl Into<Fungibles::Balance>,
|
||||
expected_active_issuance: impl Into<Fungibles::Balance>,
|
||||
) where
|
||||
Fungibles: pezframe_support::traits::fungibles::metadata::Inspect<AccountId>
|
||||
+ pezframe_support::traits::fungibles::Inspect<AccountId>,
|
||||
{
|
||||
assert_eq!(Fungibles::total_issuance(asset_id.clone().into()), expected_total_issuance.into());
|
||||
assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
|
||||
}
|
||||
|
||||
/// Helper function which emulates opening HRMP channel which is needed for `XcmpQueue` to pass.
|
||||
///
|
||||
/// Calls teyrchain-system's `create_inherent` in case the channel hasn't been opened before, and
|
||||
/// thus requires additional parameters for validating it: latest included teyrchain head and
|
||||
/// teyrchain AuRa-slot.
|
||||
///
|
||||
/// AuRa consensus hook expects pallets to be initialized, before calling this function make sure to
|
||||
/// `run_to_block` at least once.
|
||||
pub fn mock_open_hrmp_channel<
|
||||
C: cumulus_pallet_teyrchain_system::Config,
|
||||
T: ProvideInherent<Call = cumulus_pallet_teyrchain_system::Call<C>>,
|
||||
>(
|
||||
sender: ParaId,
|
||||
recipient: ParaId,
|
||||
included_head: HeaderFor<C>,
|
||||
mut slot_digest: &[u8],
|
||||
slot_durations: &SlotDurations,
|
||||
) {
|
||||
let slot = Slot::decode(&mut slot_digest).expect("failed to decode digest");
|
||||
// Convert para slot to relay chain.
|
||||
let timestamp = slot.saturating_mul(slot_durations.para.as_millis());
|
||||
let relay_slot = Slot::from_timestamp(timestamp.into(), slot_durations.relay);
|
||||
|
||||
let n = 1_u32;
|
||||
let mut sproof_builder = RelayStateSproofBuilder {
|
||||
para_id: sender,
|
||||
included_para_head: Some(HeadData(included_head.encode())),
|
||||
hrmp_egress_channel_index: Some(vec![recipient]),
|
||||
current_slot: relay_slot,
|
||||
..Default::default()
|
||||
};
|
||||
sproof_builder.hrmp_channels.insert(
|
||||
HrmpChannelId { sender, recipient },
|
||||
AbridgedHrmpChannel {
|
||||
max_capacity: 10,
|
||||
max_total_size: 10_000_000_u32,
|
||||
max_message_size: 10_000_000_u32,
|
||||
msg_count: 0,
|
||||
total_size: 0_u32,
|
||||
mqc_head: None,
|
||||
},
|
||||
);
|
||||
|
||||
let (relay_parent_storage_root, relay_chain_state) = sproof_builder.into_state_root_and_proof();
|
||||
let vfp = PersistedValidationData {
|
||||
relay_parent_number: n as RelayChainBlockNumber,
|
||||
relay_parent_storage_root,
|
||||
..Default::default()
|
||||
};
|
||||
// It is insufficient to push the validation function params
|
||||
// to storage; they must also be included in the inherent data.
|
||||
let inherent_data = {
|
||||
let mut inherent_data = InherentData::default();
|
||||
let system_inherent_data = TeyrchainInherentData {
|
||||
validation_data: vfp,
|
||||
relay_chain_state,
|
||||
downward_messages: Default::default(),
|
||||
horizontal_messages: Default::default(),
|
||||
relay_parent_descendants: Default::default(),
|
||||
collator_peer_id: None,
|
||||
};
|
||||
inherent_data
|
||||
.put_data(
|
||||
cumulus_primitives_teyrchain_inherent::INHERENT_IDENTIFIER,
|
||||
&system_inherent_data,
|
||||
)
|
||||
.expect("failed to put VFP inherent");
|
||||
inherent_data
|
||||
};
|
||||
|
||||
// execute the block
|
||||
T::create_inherent(&inherent_data)
|
||||
.expect("got an inherent")
|
||||
.dispatch_bypass_filter(RawOrigin::None.into())
|
||||
.expect("dispatch succeeded");
|
||||
}
|
||||
|
||||
impl<HrmpChannelSource: cumulus_primitives_core::XcmpMessageSource, AllPalletsWithoutSystem>
|
||||
RuntimeHelper<HrmpChannelSource, AllPalletsWithoutSystem>
|
||||
{
|
||||
pub fn take_xcm(sent_to_para_id: ParaId) -> Option<VersionedXcm<()>> {
|
||||
match HrmpChannelSource::take_outbound_messages(10)[..] {
|
||||
[(para_id, ref mut xcm_message_data)] if para_id.eq(&sent_to_para_id.into()) => {
|
||||
let mut xcm_message_data = &xcm_message_data[..];
|
||||
// decode
|
||||
let _ = XcmpMessageFormat::decode(&mut xcm_message_data).expect("valid format");
|
||||
VersionedXcm::<()>::decode_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut xcm_message_data,
|
||||
)
|
||||
.map(|x| Some(x))
|
||||
.expect("result with xcm")
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
// 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<Runtime, AllPalletsWithoutSystem = ()> =
|
||||
crate::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
|
||||
|
||||
/// Test-case makes sure that `Runtime` can change storage constant via governance-like call
|
||||
pub fn change_storage_constant_by_governance_works<Runtime, StorageConstant, StorageConstantType>(
|
||||
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||
runtime_para_id: u32,
|
||||
governance_origin: GovernanceOrigin<RuntimeOriginOf<Runtime>>,
|
||||
storage_constant_key_value: fn() -> (Vec<u8>, 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<Runtime>: From<AccountIdOf<Runtime>>,
|
||||
StorageConstant: Get<StorageConstantType>,
|
||||
StorageConstantType: Encode + PartialEq + std::fmt::Debug,
|
||||
{
|
||||
ExtBuilder::<Runtime>::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<u8>,
|
||||
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::<Runtime>::from(pezframe_system::Call::<Runtime>::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::<Runtime>::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<Runtime>(
|
||||
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||
runtime_para_id: u32,
|
||||
governance_origin: GovernanceOrigin<RuntimeOriginOf<Runtime>>,
|
||||
storage_items: Vec<(Vec<u8>, Vec<u8>)>,
|
||||
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<Runtime>: From<AccountIdOf<Runtime>>,
|
||||
{
|
||||
let mut runtime = ExtBuilder::<Runtime>::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::<Runtime>::from(pezframe_system::Call::<Runtime>::set_storage {
|
||||
items: storage_items.clone(),
|
||||
});
|
||||
|
||||
// execute XCM with Transact to `set_storage` as governance does
|
||||
assert_ok!(RuntimeHelper::<Runtime>::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<Block>
|
||||
+ pezframe_system::Config<RuntimeOrigin = RuntimeOrigin, AccountId = AccountId>
|
||||
+ pezpallet_balances::Config<Balance = u128>
|
||||
+ 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<Runtime>: From<AccountIdOf<Runtime>>,
|
||||
RuntimeOrigin: OriginTrait<AccountId = <Runtime as pezframe_system::Config>::AccountId>,
|
||||
<<Runtime as pezframe_system::Config>::Lookup as StaticLookup>::Source:
|
||||
From<<Runtime as pezframe_system::Config>::AccountId>,
|
||||
Block: BlockT,
|
||||
WeightToFee: WeightToFeeT,
|
||||
{
|
||||
use xcm::prelude::*;
|
||||
ExtBuilder::<Runtime>::default().build().execute_with(|| {
|
||||
let transfer_amount = 100u128;
|
||||
let xcm_to_weigh = Xcm::<RuntimeCall>::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<Runtime, RuntimeOrigin>(
|
||||
governance_origin: GovernanceOrigin<RuntimeOrigin>,
|
||||
) -> Result<(), Either<DispatchError, InstructionError>>
|
||||
where
|
||||
Runtime: BasicTeyrchainRuntime
|
||||
+ pezframe_system::Config<RuntimeOrigin = RuntimeOrigin, AccountId = AccountId>,
|
||||
{
|
||||
ExtBuilder::<Runtime>::default().build().execute_with(|| {
|
||||
// check before
|
||||
assert!(pezframe_system::Pallet::<Runtime>::authorized_upgrade().is_none());
|
||||
|
||||
// execute call as governance does
|
||||
let code_hash = Runtime::Hash::default();
|
||||
let authorize_upgrade_call: <Runtime as pezframe_system::Config>::RuntimeCall =
|
||||
pezframe_system::Call::<Runtime>::authorize_upgrade { code_hash }.into();
|
||||
RuntimeHelper::<Runtime>::execute_as_governance_call(
|
||||
authorize_upgrade_call,
|
||||
governance_origin,
|
||||
)?;
|
||||
|
||||
// check after
|
||||
match pezframe_system::Pallet::<Runtime>::authorized_upgrade() {
|
||||
None => Err(Either::Left(pezframe_system::Error::<Runtime>::NothingAuthorized.into())),
|
||||
Some(_) => Ok(()),
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user