Improve Penpal runtime + emulated tests (#3543)

Issues addressed in this PR:
- Improve *Penpal* runtime:
- Properly handled received assets. Previously, it treated `(1, Here)`
as the local native currency, whereas it should be treated as a
`ForeignAsset`. This wasn't a great example of standard Parachain
behaviour, as no Parachain treats the system asset as the local
currency.
- Remove `AllowExplicitUnpaidExecutionFrom` the system. Again, this
wasn't a great example of standard Parachain behaviour.
- Move duplicated
`ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger` to
`assets_common` crate.
- Improve emulated tests:
  - Update *Penpal* tests to new runtime.
- To simplify tests, register the reserve transferred, teleported, and
system assets in *Penpal* and *AssetHub* genesis. This saves us from
having to create the assets repeatedly for each test
- Add missing test case:
`reserve_transfer_assets_from_para_to_system_para`.
  - Cleanup.
- Prevent integration tests crates imports from being re-exported, as
they were polluting the `polkadot-sdk` docs.

There is still a test case missing for reserve transfers:
- Reserve transfer of system asset from *Parachain* to *Parachain*
trough *AssetHub*.
- This is not yet possible with `pallet-xcm` due to the reasons
explained in https://github.com/paritytech/polkadot-sdk/pull/3339

---------

Co-authored-by: command-bot <>
This commit is contained in:
Ignacio Palacios
2024-03-14 11:29:24 +01:00
committed by GitHub
parent 606664e1bd
commit cfc4050d6b
47 changed files with 2581 additions and 1200 deletions
@@ -53,7 +53,10 @@ use frame_system::{
limits::{BlockLength, BlockWeights},
EnsureRoot, EnsureSigned,
};
use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling};
use parachains_common::{
impls::{AssetsToBlockAuthor, NonZeroIssuance},
message_queue::{NarrowOriginToSibling, ParaIdToSibling},
};
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use smallvec::smallvec;
use sp_api::impl_runtime_apis;
@@ -70,7 +73,7 @@ use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use xcm_config::{AssetsToBlockAuthor, XcmOriginToTransactDispatchOrigin};
use xcm_config::XcmOriginToTransactDispatchOrigin;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
@@ -618,7 +621,7 @@ impl pallet_asset_tx_payment::Config for Runtime {
ConvertInto,
pallet_assets::Instance1,
>,
AssetsToBlockAuthor<Runtime>,
AssetsToBlockAuthor<Runtime, pallet_assets::Instance1>,
>;
}
@@ -23,41 +23,39 @@
//! `ReserveAssetTransferDeposited` message but that will but the intension will be to support this
//! soon.
use super::{
AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Balance, Balances,
ForeignAssets, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent,
RuntimeOrigin, WeightToFee, XcmpQueue,
AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Authorship, Balance,
Balances, ForeignAssets, ForeignAssetsInstance, NonZeroIssuance, ParachainInfo,
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee,
XcmpQueue,
};
use core::marker::PhantomData;
use frame_support::{
parameter_types,
traits::{
fungibles::{self, Balanced, Credit},
ConstU32, Contains, ContainsPair, Everything, Get, Nothing,
},
traits::{ConstU32, Contains, ContainsPair, Everything, EverythingBut, Get, Nothing},
weights::Weight,
};
use frame_system::EnsureRoot;
use pallet_asset_tx_payment::HandleCredit;
use pallet_assets::Instance1;
use pallet_xcm::XcmPassthrough;
use parachains_common::xcm_config::AssetFeeAsExistentialDepositMultiplier;
use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::impls::ToAuthor;
use sp_runtime::traits::Zero;
use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor,
FungibleAdapter, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId,
UsingComponents, WithComputedOrigin, WithUniqueTopic,
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, EnsureXcmOrigin,
FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete,
LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::{traits::JustTry, XcmExecutor};
parameter_types! {
pub const RelayLocation: Location = Location::parent();
// Local native currency which is stored in `pallet_balances``
pub const PenpalNativeCurrency: Location = Location::here();
pub const RelayNetwork: Option<NetworkId> = None;
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into();
@@ -80,7 +78,7 @@ pub type CurrencyTransactor = FungibleAdapter<
// Use this currency:
Balances,
// Use this currency when it is a fungible asset matching the given location or name:
IsConcrete<RelayLocation>,
IsConcrete<PenpalNativeCurrency>,
// Do a simple punn to convert an AccountId32 Location into a native chain account ID:
LocationToAccountId,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
@@ -123,9 +121,16 @@ pub type FungiblesTransactor = FungiblesAdapter<
CheckingAccount,
>;
/// `AssetId/Balance` converter for `TrustBackedAssets`
pub type ForeignAssetsConvertedConcreteId =
assets_common::ForeignAssetsConvertedConcreteId<StartsWith<RelayLocation>, Balance>;
pub type ForeignAssetsConvertedConcreteId = assets_common::LocationConvertedConcreteId<
EverythingBut<(
// Here we rely on fact that something like this works:
// assert!(Location::new(1,
// [Parachain(100)]).starts_with(&Location::parent()));
// assert!([Parachain(100)].into().starts_with(&Here));
StartsWith<assets_common::matching::LocalLocationPattern>,
)>,
Balance,
>;
/// Means for transacting foreign assets from different global consensus.
pub type ForeignFungiblesTransactor = FungiblesAdapter<
@@ -175,6 +180,7 @@ parameter_types! {
pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64;
pub XcmAssetFeesReceiver: Option<AccountId> = Authorship::author();
}
pub struct ParentOrParentsExecutivePlurality;
@@ -184,13 +190,6 @@ impl Contains<Location> for ParentOrParentsExecutivePlurality {
}
}
pub struct CommonGoodAssetsParachain;
impl Contains<Location> for CommonGoodAssetsParachain {
fn contains(location: &Location) -> bool {
matches!(location.unpack(), (1, [Parachain(1000)]))
}
}
pub type Barrier = TrailingSetTopicAsId<(
TakeWeightCredit,
// Expected responses are OK.
@@ -201,12 +200,6 @@ pub type Barrier = TrailingSetTopicAsId<(
// If the message is one that immediately attempts to pay for execution, then
// allow it.
AllowTopLevelPaidExecutionFrom<Everything>,
// System Assets parachain, parent and its exec plurality get free
// execution
AllowExplicitUnpaidExecutionFrom<(
CommonGoodAssetsParachain,
ParentOrParentsExecutivePlurality,
)>,
// Subscriptions for version tracking are OK.
AllowSubscriptionsFrom<Everything>,
),
@@ -246,53 +239,30 @@ impl<T: Get<Location>> ContainsPair<Asset, Location> for NativeAssetFrom<T> {
}
}
/// Allow checking in assets that have issuance > 0.
pub struct NonZeroIssuance<AccountId, Assets>(PhantomData<(AccountId, Assets)>);
impl<AccountId, Assets> Contains<<Assets as fungibles::Inspect<AccountId>>::AssetId>
for NonZeroIssuance<AccountId, Assets>
where
Assets: fungibles::Inspect<AccountId>,
{
fn contains(id: &<Assets as fungibles::Inspect<AccountId>>::AssetId) -> bool {
!Assets::total_issuance(id.clone()).is_zero()
}
}
/// A `HandleCredit` implementation that naively transfers the fees to the block author.
/// Will drop and burn the assets in case the transfer fails.
pub struct AssetsToBlockAuthor<R>(PhantomData<R>);
impl<R> HandleCredit<AccountIdOf<R>, pallet_assets::Pallet<R, Instance1>> for AssetsToBlockAuthor<R>
where
R: pallet_authorship::Config + pallet_assets::Config<Instance1>,
AccountIdOf<R>: From<polkadot_primitives::AccountId> + Into<polkadot_primitives::AccountId>,
{
fn handle_credit(credit: Credit<AccountIdOf<R>, pallet_assets::Pallet<R, Instance1>>) {
if let Some(author) = pallet_authorship::Pallet::<R>::author() {
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
let _ = pallet_assets::Pallet::<R, Instance1>::resolve(&author, credit);
}
}
}
// This asset can be added to AH as Asset and reserved transfer between Penpal and AH
pub const RESERVABLE_ASSET_ID: u32 = 1;
// This asset can be added to AH as ForeignAsset and teleported between Penpal and AH
pub const TELEPORTABLE_ASSET_ID: u32 = 2;
pub const ASSETS_PALLET_ID: u8 = 50;
pub const ASSET_HUB_ID: u32 = 1000;
parameter_types! {
/// The location that this chain recognizes as the Relay network's Asset Hub.
pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(1000)]);
// ALWAYS ensure that the index in PalletInstance stays up-to-date with
pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(ASSET_HUB_ID)]);
// the Relay Chain's Asset Hub's Assets pallet index
pub SystemAssetHubAssetsPalletLocation: Location =
Location::new(1, [Parachain(1000), PalletInstance(50)]);
Location::new(1, [Parachain(ASSET_HUB_ID), PalletInstance(ASSETS_PALLET_ID)]);
pub AssetsPalletLocation: Location =
Location::new(0, [PalletInstance(50)]);
Location::new(0, [PalletInstance(ASSETS_PALLET_ID)]);
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
pub LocalTeleportableToAssetHub: Location = Location::new(
0,
[PalletInstance(50), GeneralIndex(TELEPORTABLE_ASSET_ID.into())]
[PalletInstance(ASSETS_PALLET_ID), GeneralIndex(TELEPORTABLE_ASSET_ID.into())]
);
pub LocalTeleportableToAssetHubV3: xcm::v3::Location = xcm::v3::Location::new(
0,
[xcm::v3::Junction::PalletInstance(50), xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into())]
pub LocalReservableFromAssetHub: Location = Location::new(
1,
[Parachain(ASSET_HUB_ID), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())]
);
/// The Penpal runtime is utilized for testing with various environment setups.
@@ -337,8 +307,22 @@ impl xcm_executor::Config for XcmConfig {
type UniversalLocation = UniversalLocation;
type Barrier = Barrier;
type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
type Trader =
UsingComponents<WeightToFee, RelayLocation, AccountId, Balances, ToAuthor<Runtime>>;
type Trader = (
UsingComponents<WeightToFee, RelayLocation, AccountId, Balances, ToAuthor<Runtime>>,
// This trader allows to pay with `is_sufficient=true` "Foreign" assets from dedicated
// `pallet_assets` instance - `ForeignAssets`.
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger,
ForeignAssetsConvertedConcreteId,
ForeignAssets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
ForeignFungiblesTransactor,
AccountId,
XcmAssetFeesReceiver,
>,
>,
);
type ResponseHandler = PolkadotXcm;
type AssetTrap = PolkadotXcm;
type AssetClaims = PolkadotXcm;
@@ -356,6 +340,15 @@ impl xcm_executor::Config for XcmConfig {
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger =
AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto, ForeignAssetsInstance>,
ForeignAssetsInstance,
>;
/// No local origins on this chain are allowed to dispatch XCM sends/executions.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;