Introduce XcmFeesToAccount fee manager (#1234)

Combination of paritytech/polkadot#7005, its addon PR
paritytech/polkadot#7585 and its companion paritytech/cumulus#2433.

This PR introduces a new XcmFeesToAccount struct which implements the
`FeeManager` trait, and assigns this struct as the `FeeManager` in the
XCM config for all runtimes.

The struct simply deposits all fees handled by the XCM executor to a
specified account. In all runtimes, the specified account is configured
as the treasury account.

XCM __delivery__ fees are now being introduced (unless the root origin
is sending a message to a system parachain on behalf of the originating
chain).

# Note for reviewers

Most file changes are tests that had to be modified to account for the
new fees.
Main changes are in:
- cumulus/pallets/xcmp-queue/src/lib.rs <- To make it track the delivery
fees exponential factor
- polkadot/xcm/xcm-builder/src/fee_handling.rs <- Added. Has the
FeeManager implementation
- All runtime xcm_config files <- To add the FeeManager to the XCM
configuration

# Important note

After this change, instructions that create and send a new XCM (Query*,
Report*, ExportMessage, InitiateReserveWithdraw, InitiateTeleport,
DepositReserveAsset, TransferReserveAsset, LockAsset and RequestUnlock)
will require the corresponding origin account in the origin register to
pay for transport delivery fees, and the onward message will fail to be
sent if the origin account does not have the required amount. This
delivery fee is on top of what we already collect as tx fees in
pallet-xcm and XCM BuyExecution fees!

Wallet UIs that want to expose the new delivery fee can do so using the
formula:

```
delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee)
```

where the delivery fee factor can be obtained from the corresponding
pallet based on which transport you are using (UMP, HRMP or bridges),
the base fee is a constant, the encoded message length from the message
itself and the per byte fee is the same as the configured per byte fee
for txs (i.e. `TransactionByteFee`).

---------

Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: Giles Cope <gilescope@gmail.com>
Co-authored-by: command-bot <>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
Keith Yeung
2023-10-18 23:22:25 +08:00
committed by GitHub
parent 1cf7d3aafa
commit 3dece311be
99 changed files with 2229 additions and 468 deletions
Generated
+22
View File
@@ -798,6 +798,7 @@ version = "1.0.0"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"asset-hub-rococo-runtime", "asset-hub-rococo-runtime",
"asset-test-utils",
"frame-support", "frame-support",
"frame-system", "frame-system",
"integration-tests-common", "integration-tests-common",
@@ -810,8 +811,10 @@ dependencies = [
"polkadot-core-primitives", "polkadot-core-primitives",
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
"polkadot-runtime-parachains", "polkadot-runtime-parachains",
"rococo-runtime",
"sp-runtime", "sp-runtime",
"staging-xcm", "staging-xcm",
"staging-xcm-executor",
"xcm-emulator", "xcm-emulator",
] ]
@@ -871,6 +874,7 @@ dependencies = [
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
"polkadot-runtime-common", "polkadot-runtime-common",
"primitive-types", "primitive-types",
"rococo-runtime",
"rococo-runtime-constants", "rococo-runtime-constants",
"scale-info", "scale-info",
"smallvec", "smallvec",
@@ -899,6 +903,7 @@ version = "1.0.0"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"asset-hub-westend-runtime", "asset-hub-westend-runtime",
"asset-test-utils",
"cumulus-pallet-dmp-queue", "cumulus-pallet-dmp-queue",
"cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system",
"frame-support", "frame-support",
@@ -920,6 +925,8 @@ dependencies = [
"staging-xcm", "staging-xcm",
"staging-xcm-builder", "staging-xcm-builder",
"staging-xcm-executor", "staging-xcm-executor",
"westend-runtime",
"westend-runtime-constants",
"xcm-emulator", "xcm-emulator",
] ]
@@ -993,6 +1000,7 @@ dependencies = [
"staging-xcm-builder", "staging-xcm-builder",
"staging-xcm-executor", "staging-xcm-executor",
"substrate-wasm-builder", "substrate-wasm-builder",
"westend-runtime",
"westend-runtime-constants", "westend-runtime-constants",
] ]
@@ -2000,7 +2008,9 @@ dependencies = [
name = "bridge-hub-rococo-integration-tests" name = "bridge-hub-rococo-integration-tests"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"asset-test-utils",
"bp-messages", "bp-messages",
"bridge-hub-rococo-runtime",
"cumulus-pallet-dmp-queue", "cumulus-pallet-dmp-queue",
"cumulus-pallet-xcmp-queue", "cumulus-pallet-xcmp-queue",
"frame-support", "frame-support",
@@ -2013,6 +2023,7 @@ dependencies = [
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
"polkadot-runtime-parachains", "polkadot-runtime-parachains",
"staging-xcm", "staging-xcm",
"staging-xcm-executor",
"xcm-emulator", "xcm-emulator",
] ]
@@ -2894,6 +2905,7 @@ dependencies = [
"polkadot-core-primitives", "polkadot-core-primitives",
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
"polkadot-runtime-common", "polkadot-runtime-common",
"rococo-runtime-constants",
"scale-info", "scale-info",
"smallvec", "smallvec",
"sp-api", "sp-api",
@@ -3617,6 +3629,7 @@ dependencies = [
"log", "log",
"parity-scale-codec", "parity-scale-codec",
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
"polkadot-runtime-parachains",
"sc-client-api", "sc-client-api",
"scale-info", "scale-info",
"sp-core", "sp-core",
@@ -3701,6 +3714,7 @@ dependencies = [
"pallet-balances", "pallet-balances",
"parity-scale-codec", "parity-scale-codec",
"polkadot-runtime-common", "polkadot-runtime-common",
"polkadot-runtime-parachains",
"rand_chacha 0.3.1", "rand_chacha 0.3.1",
"scale-info", "scale-info",
"sp-core", "sp-core",
@@ -3797,8 +3811,10 @@ dependencies = [
"cumulus-primitives-core", "cumulus-primitives-core",
"frame-support", "frame-support",
"log", "log",
"pallet-xcm-benchmarks",
"parity-scale-codec", "parity-scale-codec",
"polkadot-runtime-common", "polkadot-runtime-common",
"polkadot-runtime-parachains",
"sp-io", "sp-io",
"sp-runtime", "sp-runtime",
"sp-std", "sp-std",
@@ -11095,6 +11111,7 @@ dependencies = [
"pallet-authorship", "pallet-authorship",
"pallet-balances", "pallet-balances",
"pallet-collator-selection", "pallet-collator-selection",
"parachain-info",
"parity-scale-codec", "parity-scale-codec",
"polkadot-core-primitives", "polkadot-core-primitives",
"polkadot-primitives", "polkadot-primitives",
@@ -12714,6 +12731,7 @@ dependencies = [
"pallet-transaction-payment", "pallet-transaction-payment",
"pallet-treasury", "pallet-treasury",
"pallet-vesting", "pallet-vesting",
"pallet-xcm-benchmarks",
"parity-scale-codec", "parity-scale-codec",
"polkadot-primitives", "polkadot-primitives",
"polkadot-primitives-test-helpers", "polkadot-primitives-test-helpers",
@@ -12737,6 +12755,7 @@ dependencies = [
"sp-std", "sp-std",
"staging-xcm", "staging-xcm",
"staging-xcm-builder", "staging-xcm-builder",
"staging-xcm-executor",
"static_assertions", "static_assertions",
] ]
@@ -14084,6 +14103,7 @@ dependencies = [
"parachains-common", "parachains-common",
"parity-scale-codec", "parity-scale-codec",
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
"polkadot-runtime-common",
"scale-info", "scale-info",
"sp-api", "sp-api",
"sp-block-builder", "sp-block-builder",
@@ -14216,6 +14236,7 @@ dependencies = [
"sp-core", "sp-core",
"sp-runtime", "sp-runtime",
"sp-weights", "sp-weights",
"staging-xcm",
] ]
[[package]] [[package]]
@@ -20205,6 +20226,7 @@ dependencies = [
"sp-core", "sp-core",
"sp-runtime", "sp-runtime",
"sp-weights", "sp-weights",
"staging-xcm",
] ]
[[package]] [[package]]
@@ -29,6 +29,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features
# Polkadot # Polkadot
polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]} polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default-features = false, features = [ "wasm-api" ]}
polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false }
xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false}
# Cumulus # Cumulus
@@ -63,6 +64,7 @@ std = [
"frame-system/std", "frame-system/std",
"log/std", "log/std",
"polkadot-parachain-primitives/std", "polkadot-parachain-primitives/std",
"polkadot-runtime-parachains/std",
"scale-info/std", "scale-info/std",
"sp-core/std", "sp-core/std",
"sp-externalities/std", "sp-externalities/std",
@@ -80,12 +82,14 @@ runtime-benchmarks = [
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks", "frame-system/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
] ]
try-runtime = [ try-runtime = [
"frame-support/try-runtime", "frame-support/try-runtime",
"frame-system/try-runtime", "frame-system/try-runtime",
"polkadot-runtime-parachains/try-runtime",
"sp-runtime/try-runtime", "sp-runtime/try-runtime",
] ]
+119 -10
View File
@@ -29,10 +29,10 @@
use codec::{Decode, Encode, MaxEncodedLen}; use codec::{Decode, Encode, MaxEncodedLen};
use cumulus_primitives_core::{ use cumulus_primitives_core::{
relay_chain, AbridgedHostConfiguration, ChannelStatus, CollationInfo, DmpMessageHandler, relay_chain, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo,
GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, MessageSendError, DmpMessageHandler, GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage,
OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, MessageSendError, OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage,
XcmpMessageHandler, XcmpMessageSource, UpwardMessageSender, XcmpMessageHandler, XcmpMessageSource,
}; };
use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData};
use frame_support::{ use frame_support::{
@@ -45,6 +45,7 @@ use frame_support::{
}; };
use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor}; use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor};
use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; use polkadot_parachain_primitives::primitives::RelayChainBlockNumber;
use polkadot_runtime_parachains::FeeTracker;
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_runtime::{ use sp_runtime::{
traits::{Block as BlockT, BlockNumberProvider, Hash}, traits::{Block as BlockT, BlockNumberProvider, Hash},
@@ -52,7 +53,7 @@ use sp_runtime::{
InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity, InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity,
ValidTransaction, ValidTransaction,
}, },
DispatchError, RuntimeDebug, DispatchError, FixedU128, RuntimeDebug, Saturating,
}; };
use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*}; use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
use xcm::latest::XcmHash; use xcm::latest::XcmHash;
@@ -177,6 +178,20 @@ where
check_version: bool, check_version: bool,
} }
pub mod ump_constants {
use super::FixedU128;
/// `host_config.max_upward_queue_size / THRESHOLD_FACTOR` is the threshold after which delivery
/// starts getting exponentially more expensive.
/// `2` means the price starts to increase when queue is half full.
pub const THRESHOLD_FACTOR: u32 = 2;
/// The base number the delivery fee factor gets multiplied by every time it is increased.
/// Also the number it gets divided by when decreased.
pub const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05
/// The base number message size in KB is multiplied by before increasing the fee factor.
pub const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001
}
#[frame_support::pallet] #[frame_support::pallet]
pub mod pallet { pub mod pallet {
use super::*; use super::*;
@@ -240,6 +255,10 @@ pub mod pallet {
#[pallet::hooks] #[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
/// Handles actually sending upward messages by moving them from `PendingUpwardMessages` to
/// `UpwardMessages`. Decreases the delivery fee factor if after sending messages, the queue
/// total size is less than the threshold (see [`ump_constants::THRESHOLD_FACTOR`]).
/// Also does the sending for HRMP messages it takes from `OutboundXcmpMessageSource`.
fn on_finalize(_: BlockNumberFor<T>) { fn on_finalize(_: BlockNumberFor<T>) {
<DidSetValidationCode<T>>::kill(); <DidSetValidationCode<T>>::kill();
<UpgradeRestrictionSignal<T>>::kill(); <UpgradeRestrictionSignal<T>>::kill();
@@ -326,6 +345,17 @@ pub mod pallet {
UpwardMessages::<T>::put(&up[..num as usize]); UpwardMessages::<T>::put(&up[..num as usize]);
*up = up.split_off(num as usize); *up = up.split_off(num as usize);
// If the total size of the pending messages is less than the threshold,
// we decrease the fee factor, since the queue is less congested.
// This makes delivery of new messages cheaper.
let threshold = host_config
.max_upward_queue_size
.saturating_div(ump_constants::THRESHOLD_FACTOR);
let remaining_total_size: usize = up.iter().map(UpwardMessage::len).sum();
if remaining_total_size <= threshold as usize {
Self::decrease_fee_factor(());
}
(num, total_size) (num, total_size)
}); });
@@ -721,7 +751,7 @@ pub mod pallet {
StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>; StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;
/// Storage field that keeps track of bandwidth used by the unincluded segment along with the /// Storage field that keeps track of bandwidth used by the unincluded segment along with the
/// latest the latest HRMP watermark. Used for limiting the acceptance of new blocks with /// latest HRMP watermark. Used for limiting the acceptance of new blocks with
/// respect to relay chain constraints. /// respect to relay chain constraints.
#[pallet::storage] #[pallet::storage]
pub(super) type AggregatedUnincludedSegment<T: Config> = pub(super) type AggregatedUnincludedSegment<T: Config> =
@@ -860,6 +890,17 @@ pub mod pallet {
pub(super) type PendingUpwardMessages<T: Config> = pub(super) type PendingUpwardMessages<T: Config> =
StorageValue<_, Vec<UpwardMessage>, ValueQuery>; StorageValue<_, Vec<UpwardMessage>, ValueQuery>;
/// Initialization value for the delivery fee factor for UMP.
#[pallet::type_value]
pub fn UpwardInitialDeliveryFeeFactor() -> FixedU128 {
FixedU128::from_u32(1)
}
/// The factor to multiply the base delivery fee by for UMP.
#[pallet::storage]
pub(super) type UpwardDeliveryFeeFactor<T: Config> =
StorageValue<_, FixedU128, ValueQuery, UpwardInitialDeliveryFeeFactor>;
/// The number of HRMP messages we observed in `on_initialize` and thus used that number for /// The number of HRMP messages we observed in `on_initialize` and thus used that number for
/// announcing the weight of `on_initialize` and `on_finalize`. /// announcing the weight of `on_initialize` and `on_finalize`.
#[pallet::storage] #[pallet::storage]
@@ -976,6 +1017,31 @@ impl<T: Config> Pallet<T> {
} }
} }
impl<T: Config> FeeTracker for Pallet<T> {
type Id = ();
fn get_fee_factor(_: Self::Id) -> FixedU128 {
UpwardDeliveryFeeFactor::<T>::get()
}
fn increase_fee_factor(_: Self::Id, message_size_factor: FixedU128) -> FixedU128 {
<UpwardDeliveryFeeFactor<T>>::mutate(|f| {
*f = f.saturating_mul(
ump_constants::EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor),
);
*f
})
}
fn decrease_fee_factor(_: Self::Id) -> FixedU128 {
<UpwardDeliveryFeeFactor<T>>::mutate(|f| {
*f =
UpwardInitialDeliveryFeeFactor::get().max(*f / ump_constants::EXPONENTIAL_FEE_BASE);
*f
})
}
}
impl<T: Config> GetChannelInfo for Pallet<T> { impl<T: Config> GetChannelInfo for Pallet<T> {
fn get_channel_status(id: ParaId) -> ChannelStatus { fn get_channel_status(id: ParaId) -> ChannelStatus {
// Note, that we are using `relevant_messaging_state` which may be from the previous // Note, that we are using `relevant_messaging_state` which may be from the previous
@@ -1019,10 +1085,17 @@ impl<T: Config> GetChannelInfo for Pallet<T> {
ChannelStatus::Ready(max_size_now as usize, max_size_ever as usize) ChannelStatus::Ready(max_size_now as usize, max_size_ever as usize)
} }
fn get_channel_max(id: ParaId) -> Option<usize> { fn get_channel_info(id: ParaId) -> Option<ChannelInfo> {
let channels = Self::relevant_messaging_state()?.egress_channels; let channels = Self::relevant_messaging_state()?.egress_channels;
let index = channels.binary_search_by_key(&id, |item| item.0).ok()?; let index = channels.binary_search_by_key(&id, |item| item.0).ok()?;
Some(channels[index].1.max_message_size as usize) let info = ChannelInfo {
max_capacity: channels[index].1.max_capacity,
max_total_size: channels[index].1.max_total_size,
max_message_size: channels[index].1.max_message_size,
msg_count: channels[index].1.msg_count,
total_size: channels[index].1.total_size,
};
Some(info)
} }
} }
@@ -1427,6 +1500,23 @@ impl<T: Config> Pallet<T> {
}) })
} }
/// Open HRMP channel for using it in benchmarks or tests.
///
/// The caller assumes that the pallet will accept regular outbound message to the sibling
/// `target_parachain` after this call. No other assumptions are made.
#[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
pub fn open_custom_outbound_hrmp_channel_for_benchmarks_or_tests(
target_parachain: ParaId,
channel: cumulus_primitives_core::AbridgedHrmpChannel,
) {
RelevantMessagingState::<T>::put(MessagingStateSnapshot {
dmq_mqc_head: Default::default(),
relay_dispatch_queue_remaining_capacity: Default::default(),
ingress_channels: Default::default(),
egress_channels: vec![(target_parachain, channel)],
})
}
/// Prepare/insert relevant data for `schedule_code_upgrade` for benchmarks. /// Prepare/insert relevant data for `schedule_code_upgrade` for benchmarks.
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
pub fn initialize_for_set_code_benchmark(max_code_size: u32) { pub fn initialize_for_set_code_benchmark(max_code_size: u32) {
@@ -1468,7 +1558,13 @@ impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
} }
impl<T: Config> Pallet<T> { impl<T: Config> Pallet<T> {
/// Puts a message in the `PendingUpwardMessages` storage item.
/// The message will be later sent in `on_finalize`.
/// Checks host configuration to see if message is too big.
/// Increases the delivery fee factor if the queue is sufficiently (see
/// [`ump_constants::THRESHOLD_FACTOR`]) congested.
pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> { pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
let message_len = message.len();
// Check if the message fits into the relay-chain constraints. // Check if the message fits into the relay-chain constraints.
// //
// Note, that we are using `host_configuration` here which may be from the previous // Note, that we are using `host_configuration` here which may be from the previous
@@ -1482,9 +1578,22 @@ impl<T: Config> Pallet<T> {
// //
// However, changing this setting is expected to be rare. // However, changing this setting is expected to be rare.
if let Some(cfg) = Self::host_configuration() { if let Some(cfg) = Self::host_configuration() {
if message.len() > cfg.max_upward_message_size as usize { if message_len > cfg.max_upward_message_size as usize {
return Err(MessageSendError::TooBig) return Err(MessageSendError::TooBig)
} }
let threshold =
cfg.max_upward_queue_size.saturating_div(ump_constants::THRESHOLD_FACTOR);
// We check the threshold against total size and not number of messages since messages
// could be big or small.
<PendingUpwardMessages<T>>::append(message.clone());
let pending_messages = PendingUpwardMessages::<T>::get();
let total_size: usize = pending_messages.iter().map(UpwardMessage::len).sum();
if total_size > threshold as usize {
// We increase the fee factor by a factor based on the new message's size in KB
let message_size_factor = FixedU128::from((message_len / 1024) as u128)
.saturating_mul(ump_constants::MESSAGE_SIZE_FEE_BASE);
Self::increase_fee_factor((), message_size_factor);
}
} else { } else {
// This storage field should carry over from the previous block. So if it's None // This storage field should carry over from the previous block. So if it's None
// then it must be that this is an edge-case where a message is attempted to be // then it must be that this is an edge-case where a message is attempted to be
@@ -1495,8 +1604,8 @@ impl<T: Config> Pallet<T> {
// returned back to the sender. // returned back to the sender.
// //
// Thus fall through here. // Thus fall through here.
<PendingUpwardMessages<T>>::append(message.clone());
}; };
<PendingUpwardMessages<T>>::append(message.clone());
// The relay ump does not use using_encoded // The relay ump does not use using_encoded
// We apply the same this to use the same hash // We apply the same this to use the same hash
@@ -1496,3 +1496,53 @@ fn deposits_relay_parent_storage_root() {
}, },
); );
} }
#[test]
fn ump_fee_factor_increases_and_decreases() {
BlockTests::new()
.with_relay_sproof_builder(|_, _, sproof| {
sproof.host_config.max_upward_queue_size = 100;
sproof.host_config.max_upward_message_num_per_candidate = 1;
})
.add_with_post_test(
1,
|| {
// Fee factor increases in `send_upward_message`
ParachainSystem::send_upward_message(b"Test".to_vec()).unwrap();
assert_eq!(UpwardDeliveryFeeFactor::<Test>::get(), FixedU128::from_u32(1));
ParachainSystem::send_upward_message(
b"This message will be enough to increase the fee factor".to_vec(),
)
.unwrap();
assert_eq!(
UpwardDeliveryFeeFactor::<Test>::get(),
FixedU128::from_rational(105, 100)
);
},
|| {
// Factor decreases in `on_finalize`, but only if we are below the threshold
let messages = UpwardMessages::<Test>::get();
assert_eq!(messages, vec![b"Test".to_vec()]);
assert_eq!(
UpwardDeliveryFeeFactor::<Test>::get(),
FixedU128::from_rational(105, 100)
);
},
)
.add_with_post_test(
2,
|| {
// We do nothing here
},
|| {
let messages = UpwardMessages::<Test>::get();
assert_eq!(
messages,
vec![b"This message will be enough to increase the fee factor".to_vec(),]
);
// Now the delivery fee factor is decreased, since we are below the threshold
assert_eq!(UpwardDeliveryFeeFactor::<Test>::get(), FixedU128::from_u32(1));
},
);
}
+9 -3
View File
@@ -14,13 +14,15 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive"
frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-support = { path = "../../../substrate/frame/support", default-features = false}
frame-system = { path = "../../../substrate/frame/system", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false}
sp-io = { path = "../../../substrate/primitives/io", default-features = false} sp-io = { path = "../../../substrate/primitives/io", default-features = false}
sp-core = { path = "../../../substrate/primitives/core", default-features = false }
sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false} sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false}
sp-std = { path = "../../../substrate/primitives/std", default-features = false} sp-std = { path = "../../../substrate/primitives/std", default-features = false}
# Polkadot # Polkadot
polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false }
xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false }
# Cumulus # Cumulus
cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
@@ -54,7 +56,9 @@ std = [
"frame-system/std", "frame-system/std",
"log/std", "log/std",
"polkadot-runtime-common/std", "polkadot-runtime-common/std",
"polkadot-runtime-parachains/std",
"scale-info/std", "scale-info/std",
"sp-core/std",
"sp-io/std", "sp-io/std",
"sp-runtime/std", "sp-runtime/std",
"sp-std/std", "sp-std/std",
@@ -69,6 +73,7 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks", "frame-system/runtime-benchmarks",
"pallet-balances/runtime-benchmarks", "pallet-balances/runtime-benchmarks",
"polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks", "xcm-executor/runtime-benchmarks",
@@ -79,6 +84,7 @@ try-runtime = [
"frame-system/try-runtime", "frame-system/try-runtime",
"pallet-balances/try-runtime", "pallet-balances/try-runtime",
"polkadot-runtime-common/try-runtime", "polkadot-runtime-common/try-runtime",
"polkadot-runtime-parachains/try-runtime",
"sp-runtime/try-runtime", "sp-runtime/try-runtime",
] ]
bridging = [ "bp-xcm-bridge-hub-router" ] bridging = [ "bp-xcm-bridge-hub-router" ]
+158 -43
View File
@@ -22,6 +22,16 @@
//! Also provides an implementation of `SendXcm` which can be placed in a router tuple for relaying //! Also provides an implementation of `SendXcm` which can be placed in a router tuple for relaying
//! XCM over XCMP if the destination is `Parent/Parachain`. It requires an implementation of //! XCM over XCMP if the destination is `Parent/Parachain`. It requires an implementation of
//! `XcmExecutor` for dispatching incoming XCM messages. //! `XcmExecutor` for dispatching incoming XCM messages.
//!
//! To prevent out of memory errors on the `OutboundXcmpMessages` queue, an exponential fee factor
//! (`DeliveryFeeFactor`) is set, much like the one used in DMP.
//! The fee factor increases whenever the total size of messages in a particular channel passes a
//! threshold. This threshold is defined as a percentage of the maximum total size the channel can
//! have. More concretely, the threshold is `max_total_size` / `THRESHOLD_FACTOR`, where:
//! - `max_total_size` is the maximum size, in bytes, of the channel, not number of messages.
//! It is defined in the channel configuration.
//! - `THRESHOLD_FACTOR` just declares which percentage of the max size is the actual threshold.
//! If it's 2, then the threshold is half of the max size, if it's 4, it's a quarter, and so on.
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
@@ -49,13 +59,15 @@ use frame_support::{
traits::{EnsureOrigin, Get}, traits::{EnsureOrigin, Get},
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight},
}; };
use polkadot_runtime_common::xcm_sender::PriceForParachainDelivery; use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery;
use polkadot_runtime_parachains::FeeTracker;
use rand_chacha::{ use rand_chacha::{
rand_core::{RngCore, SeedableRng}, rand_core::{RngCore, SeedableRng},
ChaChaRng, ChaChaRng,
}; };
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug; use sp_core::MAX_POSSIBLE_ALLOCATION;
use sp_runtime::{FixedU128, RuntimeDebug, Saturating};
use sp_std::{convert::TryFrom, prelude::*}; use sp_std::{convert::TryFrom, prelude::*};
use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH};
use xcm_executor::traits::ConvertOrigin; use xcm_executor::traits::ConvertOrigin;
@@ -68,6 +80,19 @@ pub type OverweightIndex = u64;
const LOG_TARGET: &str = "xcmp_queue"; const LOG_TARGET: &str = "xcmp_queue";
const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB
/// Constants related to delivery fee calculation
pub mod delivery_fee_constants {
use super::FixedU128;
/// Fees will start increasing when queue is half full
pub const THRESHOLD_FACTOR: u32 = 2;
/// The base number the delivery fee factor gets multiplied by every time it is increased.
/// Also, the number it gets divided by when decreased.
pub const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05
/// The contribution of each KB to a fee factor increase
pub const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001
}
// Maximum amount of messages to process per block. This is a temporary measure until we properly // Maximum amount of messages to process per block. This is a temporary measure until we properly
// account for proof size weights. // account for proof size weights.
const MAX_MESSAGES_PER_BLOCK: u8 = 10; const MAX_MESSAGES_PER_BLOCK: u8 = 10;
@@ -77,7 +102,7 @@ const MAX_OVERWEIGHT_MESSAGES: u32 = 1000;
#[frame_support::pallet] #[frame_support::pallet]
pub mod pallet { pub mod pallet {
use super::*; use super::*;
use frame_support::pallet_prelude::*; use frame_support::{pallet_prelude::*, Twox64Concat};
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
#[pallet::pallet] #[pallet::pallet]
@@ -109,7 +134,7 @@ pub mod pallet {
type ControllerOriginConverter: ConvertOrigin<Self::RuntimeOrigin>; type ControllerOriginConverter: ConvertOrigin<Self::RuntimeOrigin>;
/// The price for delivering an XCM to a sibling parachain destination. /// The price for delivering an XCM to a sibling parachain destination.
type PriceForSiblingDelivery: PriceForParachainDelivery; type PriceForSiblingDelivery: PriceForMessageDelivery<Id = ParaId>;
/// The weight information of this pallet. /// The weight information of this pallet.
type WeightInfo: WeightInfo; type WeightInfo: WeightInfo;
@@ -374,6 +399,17 @@ pub mod pallet {
/// Whether or not the XCMP queue is suspended from executing incoming XCMs or not. /// Whether or not the XCMP queue is suspended from executing incoming XCMs or not.
#[pallet::storage] #[pallet::storage]
pub(super) type QueueSuspended<T: Config> = StorageValue<_, bool, ValueQuery>; pub(super) type QueueSuspended<T: Config> = StorageValue<_, bool, ValueQuery>;
/// Initialization value for the DeliveryFee factor.
#[pallet::type_value]
pub fn InitialFactor() -> FixedU128 {
FixedU128::from_u32(1)
}
/// The factor to multiply the base delivery fee by.
#[pallet::storage]
pub(super) type DeliveryFeeFactor<T: Config> =
StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>;
} }
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)]
@@ -403,7 +439,7 @@ pub struct InboundChannelDetails {
} }
/// Struct containing detailed information about the outbound channel. /// Struct containing detailed information about the outbound channel.
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] #[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct OutboundChannelDetails { pub struct OutboundChannelDetails {
/// The `ParaId` of the parachain that this channel is connected with. /// The `ParaId` of the parachain that this channel is connected with.
recipient: ParaId, recipient: ParaId,
@@ -503,56 +539,90 @@ impl<T: Config> Pallet<T> {
/// length prefixed and can thus decode each fragment from the aggregate stream. With this, /// length prefixed and can thus decode each fragment from the aggregate stream. With this,
/// we can concatenate them into a single aggregate blob without needing to be concerned /// we can concatenate them into a single aggregate blob without needing to be concerned
/// about encoding fragment boundaries. /// about encoding fragment boundaries.
///
/// If successful, returns the number of pages in the outbound queue after enqueuing the new
/// fragment.
fn send_fragment<Fragment: Encode>( fn send_fragment<Fragment: Encode>(
recipient: ParaId, recipient: ParaId,
format: XcmpMessageFormat, format: XcmpMessageFormat,
fragment: Fragment, fragment: Fragment,
) -> Result<u32, MessageSendError> { ) -> Result<u32, MessageSendError> {
let data = fragment.encode(); let encoded_fragment = fragment.encode();
// Optimization note: `max_message_size` could potentially be stored in let channel_info =
// `OutboundXcmpMessages` once known; that way it's only accessed when a new page is needed. T::ChannelInfo::get_channel_info(recipient).ok_or(MessageSendError::NoChannel)?;
let max_message_size = channel_info.max_message_size as usize;
let max_message_size = // Max message size refers to aggregates, or pages. Not to individual fragments.
T::ChannelInfo::get_channel_max(recipient).ok_or(MessageSendError::NoChannel)?; if encoded_fragment.len() > max_message_size {
if data.len() > max_message_size {
return Err(MessageSendError::TooBig) return Err(MessageSendError::TooBig)
} }
let mut s = <OutboundXcmpStatus<T>>::get(); let mut all_channels = <OutboundXcmpStatus<T>>::get();
let details = if let Some(details) = s.iter_mut().find(|item| item.recipient == recipient) { let channel_details = if let Some(details) =
all_channels.iter_mut().find(|channel| channel.recipient == recipient)
{
details details
} else { } else {
s.push(OutboundChannelDetails::new(recipient)); all_channels.push(OutboundChannelDetails::new(recipient));
s.last_mut().expect("can't be empty; a new element was just pushed; qed") all_channels
.last_mut()
.expect("can't be empty; a new element was just pushed; qed")
}; };
let have_active = details.last_index > details.first_index; let have_active = channel_details.last_index > channel_details.first_index;
let appended = have_active && // Try to append fragment to the last page, if there is enough space.
<OutboundXcmpMessages<T>>::mutate(recipient, details.last_index - 1, |s| { // We return the size of the last page inside of the option, to not calculate it again.
if XcmpMessageFormat::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut &s[..]) != let appended_to_last_page = have_active
Ok(format) .then(|| {
{ <OutboundXcmpMessages<T>>::mutate(
return false recipient,
} channel_details.last_index - 1,
if s.len() + data.len() > max_message_size { |page| {
return false if XcmpMessageFormat::decode_with_depth_limit(
} MAX_XCM_DECODE_DEPTH,
s.extend_from_slice(&data[..]); &mut &page[..],
true ) != Ok(format)
}); {
if appended { return None
Ok((details.last_index - details.first_index - 1) as u32) }
if page.len() + encoded_fragment.len() > max_message_size {
return None
}
page.extend_from_slice(&encoded_fragment[..]);
Some(page.len())
},
)
})
.flatten();
let (number_of_pages, last_page_size) = if let Some(size) = appended_to_last_page {
let number_of_pages = (channel_details.last_index - channel_details.first_index) as u32;
(number_of_pages, size)
} else { } else {
// Need to add a new page. // Need to add a new page.
let page_index = details.last_index; let page_index = channel_details.last_index;
details.last_index += 1; channel_details.last_index += 1;
let mut new_page = format.encode(); let mut new_page = format.encode();
new_page.extend_from_slice(&data[..]); new_page.extend_from_slice(&encoded_fragment[..]);
let last_page_size = new_page.len();
let number_of_pages = (channel_details.last_index - channel_details.first_index) as u32;
<OutboundXcmpMessages<T>>::insert(recipient, page_index, new_page); <OutboundXcmpMessages<T>>::insert(recipient, page_index, new_page);
let r = (details.last_index - details.first_index - 1) as u32; <OutboundXcmpStatus<T>>::put(all_channels);
<OutboundXcmpStatus<T>>::put(s); (number_of_pages, last_page_size)
Ok(r) };
// We have to count the total size here since `channel_info.total_size` is not updated at
// this point in time. We assume all previous pages are filled, which, in practice, is not
// always the case.
let total_size =
number_of_pages.saturating_sub(1) * max_message_size as u32 + last_page_size as u32;
let threshold = channel_info.max_total_size / delivery_fee_constants::THRESHOLD_FACTOR;
if total_size > threshold {
let message_size_factor = FixedU128::from((encoded_fragment.len() / 1024) as u128)
.saturating_mul(delivery_fee_constants::MESSAGE_SIZE_FEE_BASE);
Self::increase_fee_factor(recipient, message_size_factor);
} }
Ok(number_of_pages)
} }
/// Sends a signal to the `dest` chain over XCMP. This is guaranteed to be dispatched on this /// Sends a signal to the `dest` chain over XCMP. This is guaranteed to be dispatched on this
@@ -1004,9 +1074,8 @@ impl<T: Config> XcmpMessageHandler for Pallet<T> {
// Record the fact we received it. // Record the fact we received it.
match status.binary_search_by_key(&sender, |item| item.sender) { match status.binary_search_by_key(&sender, |item| item.sender) {
Ok(i) => { Ok(i) => {
let count = status[i].message_metadata.len(); let count = status[i].message_metadata.len() as u32;
if count as u32 >= suspend_threshold && status[i].state == InboundState::Ok if count >= suspend_threshold && status[i].state == InboundState::Ok {
{
status[i].state = InboundState::Suspended; status[i].state = InboundState::Suspended;
let r = Self::send_signal(sender, ChannelSignal::Suspend); let r = Self::send_signal(sender, ChannelSignal::Suspend);
if r.is_err() { if r.is_err() {
@@ -1015,7 +1084,7 @@ impl<T: Config> XcmpMessageHandler for Pallet<T> {
); );
} }
} }
if (count as u32) < drop_threshold { if count < drop_threshold {
status[i].message_metadata.push((sent_at, format)); status[i].message_metadata.push((sent_at, format));
} else { } else {
debug_assert!( debug_assert!(
@@ -1023,6 +1092,13 @@ impl<T: Config> XcmpMessageHandler for Pallet<T> {
"XCMP channel queue full. Silently dropping message" "XCMP channel queue full. Silently dropping message"
); );
} }
// Update the delivery fee factor, if applicable.
if count > suspend_threshold {
let message_size_factor =
FixedU128::from((data_ref.len() / 1024) as u128)
.saturating_mul(delivery_fee_constants::MESSAGE_SIZE_FEE_BASE);
Self::increase_fee_factor(sender, message_size_factor);
}
}, },
Err(_) => status.push(InboundChannelDetails { Err(_) => status.push(InboundChannelDetails {
sender, sender,
@@ -1120,6 +1196,21 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {
result.push((para_id, page)); result.push((para_id, page));
} }
let max_total_size = match T::ChannelInfo::get_channel_info(para_id) {
Some(channel_info) => channel_info.max_total_size,
None => {
log::warn!("calling `get_channel_info` with no RelevantMessagingState?!");
MAX_POSSIBLE_ALLOCATION // We use this as a fallback in case the messaging state is not present
},
};
let threshold = max_total_size.saturating_div(delivery_fee_constants::THRESHOLD_FACTOR);
let remaining_total_size: usize = (first_index..last_index)
.map(|index| OutboundXcmpMessages::<T>::decode_len(para_id, index).unwrap())
.sum();
if remaining_total_size <= threshold as usize {
Self::decrease_fee_factor(para_id);
}
*status = OutboundChannelDetails { *status = OutboundChannelDetails {
recipient: para_id, recipient: para_id,
state: outbound_state, state: outbound_state,
@@ -1172,7 +1263,7 @@ impl<T: Config> SendXcm for Pallet<T> {
MultiLocation { parents: 1, interior: X1(Parachain(id)) } => { MultiLocation { parents: 1, interior: X1(Parachain(id)) } => {
let xcm = msg.take().ok_or(SendError::MissingArgument)?; let xcm = msg.take().ok_or(SendError::MissingArgument)?;
let id = ParaId::from(*id); let id = ParaId::from(*id);
let price = T::PriceForSiblingDelivery::price_for_parachain_delivery(id, &xcm); let price = T::PriceForSiblingDelivery::price_for_delivery(id, &xcm);
let versioned_xcm = T::VersionWrapper::wrap_version(&d, xcm) let versioned_xcm = T::VersionWrapper::wrap_version(&d, xcm)
.map_err(|()| SendError::DestinationUnsupported)?; .map_err(|()| SendError::DestinationUnsupported)?;
Ok(((id, versioned_xcm), price)) Ok(((id, versioned_xcm), price))
@@ -1198,3 +1289,27 @@ impl<T: Config> SendXcm for Pallet<T> {
} }
} }
} }
impl<T: Config> FeeTracker for Pallet<T> {
type Id = ParaId;
fn get_fee_factor(id: Self::Id) -> FixedU128 {
<DeliveryFeeFactor<T>>::get(id)
}
fn increase_fee_factor(id: Self::Id, message_size_factor: FixedU128) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(id, |f| {
*f = f.saturating_mul(
delivery_fee_constants::EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor),
);
*f
})
}
fn decrease_fee_factor(id: Self::Id) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(id, |f| {
*f = InitialFactor::get().max(*f / delivery_fee_constants::EXPONENTIAL_FEE_BASE);
*f
})
}
}
+20 -2
View File
@@ -85,8 +85,10 @@ parameter_types! {
pub const MaxReserves: u32 = 50; pub const MaxReserves: u32 = 50;
} }
pub type Balance = u64;
impl pallet_balances::Config for Test { impl pallet_balances::Config for Test {
type Balance = u64; type Balance = Balance;
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DustRemoval = (); type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit; type ExistentialDeposit = ExistentialDeposit;
@@ -196,6 +198,22 @@ impl<RuntimeOrigin: OriginTrait> ConvertOrigin<RuntimeOrigin>
} }
} }
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(RelayChain::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: Balance = 300_000_000;
/// The fee per byte
pub const ByteFee: Balance = 1_000_000;
}
pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
ByteFee,
XcmpQueue,
>;
impl Config for Test { impl Config for Test {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>; type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
@@ -205,7 +223,7 @@ impl Config for Test {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = SystemParachainAsSuperuser<RuntimeOrigin>; type ControllerOriginConverter = SystemParachainAsSuperuser<RuntimeOrigin>;
type WeightInfo = (); type WeightInfo = ();
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
} }
pub fn new_test_ext() -> sp_io::TestExternalities { pub fn new_test_ext() -> sp_io::TestExternalities {
+77 -5
View File
@@ -324,13 +324,14 @@ fn xcmp_queue_consumes_dest_and_msg_on_ok_validate() {
let dest = (Parent, X1(Parachain(5555))); let dest = (Parent, X1(Parachain(5555)));
let mut dest_wrapper = Some(dest.into()); let mut dest_wrapper = Some(dest.into());
let mut msg_wrapper = Some(message.clone()); let mut msg_wrapper = Some(message.clone());
assert!(<XcmpQueue as SendXcm>::validate(&mut dest_wrapper, &mut msg_wrapper).is_ok());
// check wrapper were consumed
assert_eq!(None, dest_wrapper.take());
assert_eq!(None, msg_wrapper.take());
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
assert!(<XcmpQueue as SendXcm>::validate(&mut dest_wrapper, &mut msg_wrapper).is_ok());
// check wrapper were consumed
assert_eq!(None, dest_wrapper.take());
assert_eq!(None, msg_wrapper.take());
// another try with router chain with asserting sender // another try with router chain with asserting sender
assert_eq!( assert_eq!(
Err(SendError::Transport("NoChannel")), Err(SendError::Transport("NoChannel")),
@@ -370,3 +371,74 @@ fn xcmp_queue_send_xcm_works() {
.any(|(para_id, _)| para_id == &sibling_para_id)); .any(|(para_id, _)| para_id == &sibling_para_id));
}) })
} }
#[test]
fn verify_fee_factor_increase_and_decrease() {
use cumulus_primitives_core::AbridgedHrmpChannel;
use sp_runtime::FixedU128;
let sibling_para_id = ParaId::from(12345);
let destination = (Parent, Parachain(sibling_para_id.into())).into();
let xcm = Xcm(vec![ClearOrigin; 100]);
let versioned_xcm = VersionedXcm::from(xcm.clone());
let mut xcmp_message = XcmpMessageFormat::ConcatenatedVersionedXcm.encode();
xcmp_message.extend(versioned_xcm.encode());
new_test_ext().execute_with(|| {
let initial = InitialFactor::get();
assert_eq!(DeliveryFeeFactor::<Test>::get(sibling_para_id), initial);
// Open channel so messages can actually be sent
ParachainSystem::open_custom_outbound_hrmp_channel_for_benchmarks_or_tests(
sibling_para_id,
AbridgedHrmpChannel {
max_capacity: 10,
max_total_size: 1000,
max_message_size: 104,
msg_count: 0,
total_size: 0,
mqc_head: None,
},
);
// Fee factor is only increased in `send_fragment`, which is called by `send_xcm`.
// When queue is not congested, fee factor doesn't change.
assert_ok!(send_xcm::<XcmpQueue>(destination, xcm.clone())); // Size 104
assert_ok!(send_xcm::<XcmpQueue>(destination, xcm.clone())); // Size 208
assert_ok!(send_xcm::<XcmpQueue>(destination, xcm.clone())); // Size 312
assert_ok!(send_xcm::<XcmpQueue>(destination, xcm.clone())); // Size 416
assert_eq!(DeliveryFeeFactor::<Test>::get(sibling_para_id), initial);
// Sending the message right now is cheap
let (_, delivery_fees) = validate_send::<XcmpQueue>(destination, xcm.clone())
.expect("message can be sent; qed");
let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); };
assert_eq!(delivery_fee_amount, 402_000_000);
let smaller_xcm = Xcm(vec![ClearOrigin; 30]);
// When we get to half of `max_total_size`, because `THRESHOLD_FACTOR` is 2,
// then the fee factor starts to increase.
assert_ok!(send_xcm::<XcmpQueue>(destination, xcm.clone())); // Size 520
assert_eq!(DeliveryFeeFactor::<Test>::get(sibling_para_id), FixedU128::from_float(1.05));
for _ in 0..12 { // We finish at size 929
assert_ok!(send_xcm::<XcmpQueue>(destination, smaller_xcm.clone()));
}
assert!(DeliveryFeeFactor::<Test>::get(sibling_para_id) > FixedU128::from_float(1.88));
// Sending the message right now is expensive
let (_, delivery_fees) = validate_send::<XcmpQueue>(destination, xcm.clone())
.expect("message can be sent; qed");
let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); };
assert_eq!(delivery_fee_amount, 758_030_955);
// Fee factor only decreases in `take_outbound_messages`
for _ in 0..5 { // We take 5 100 byte pages
XcmpQueue::take_outbound_messages(1);
}
assert!(DeliveryFeeFactor::<Test>::get(sibling_para_id) < FixedU128::from_float(1.72));
XcmpQueue::take_outbound_messages(1);
assert!(DeliveryFeeFactor::<Test>::get(sibling_para_id) < FixedU128::from_float(1.63));
});
}
@@ -10,6 +10,8 @@ mod weights;
pub mod xcm_config; pub mod xcm_config;
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use smallvec::smallvec; use smallvec::smallvec;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
@@ -412,7 +414,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = (); type WeightInfo = ();
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
+2
View File
@@ -40,6 +40,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false }
parachain-info = { path = "../pallets/parachain-info", default-features = false }
[dev-dependencies] [dev-dependencies]
pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false} pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false}
@@ -61,6 +62,7 @@ std = [
"pallet-authorship/std", "pallet-authorship/std",
"pallet-balances/std", "pallet-balances/std",
"pallet-collator-selection/std", "pallet-collator-selection/std",
"parachain-info/std",
"polkadot-core-primitives/std", "polkadot-core-primitives/std",
"polkadot-primitives/std", "polkadot-primitives/std",
"rococo-runtime-constants/std", "rococo-runtime-constants/std",
+7 -1
View File
@@ -73,7 +73,10 @@ mod types {
/// Common constants of parachains. /// Common constants of parachains.
mod constants { mod constants {
use super::types::BlockNumber; use super::types::BlockNumber;
use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}; use frame_support::{
weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
PalletId,
};
use sp_runtime::Perbill; use sp_runtime::Perbill;
/// This determines the average expected block time that we are targeting. Blocks will be /// This determines the average expected block time that we are targeting. Blocks will be
/// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by /// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by
@@ -101,6 +104,9 @@ mod constants {
WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), WEIGHT_REF_TIME_PER_SECOND.saturating_div(2),
polkadot_primitives::MAX_POV_SIZE as u64, polkadot_primitives::MAX_POV_SIZE as u64,
); );
/// Treasury pallet id of the local chain, used to convert into AccountId
pub const TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry");
} }
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
+22 -2
View File
@@ -16,10 +16,9 @@
use crate::impls::AccountIdOf; use crate::impls::AccountIdOf;
use cumulus_primitives_core::{IsSystem, ParaId}; use cumulus_primitives_core::{IsSystem, ParaId};
use frame_support::{ use frame_support::{
traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, ContainsPair}, traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, Contains, ContainsPair},
weights::Weight, weights::Weight,
}; };
use log;
use sp_runtime::traits::Get; use sp_runtime::traits::Get;
use sp_std::marker::PhantomData; use sp_std::marker::PhantomData;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
@@ -80,6 +79,27 @@ impl<Location: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation>
} }
} }
pub struct RelayOrOtherSystemParachains<
SystemParachainMatcher: Contains<MultiLocation>,
Runtime: parachain_info::Config,
> {
_runtime: PhantomData<(SystemParachainMatcher, Runtime)>,
}
impl<SystemParachainMatcher: Contains<MultiLocation>, Runtime: parachain_info::Config>
Contains<MultiLocation> for RelayOrOtherSystemParachains<SystemParachainMatcher, Runtime>
{
fn contains(l: &MultiLocation) -> bool {
let self_para_id: u32 = parachain_info::Pallet::<Runtime>::get().into();
if let MultiLocation { parents: 0, interior: X1(Parachain(para_id)) } = l {
if *para_id == self_para_id {
return false
}
}
matches!(l, MultiLocation { parents: 1, interior: Here }) ||
SystemParachainMatcher::contains(l)
}
}
/// Accepts an asset if it is a concrete asset from the system (Relay Chain or system parachain). /// Accepts an asset if it is a concrete asset from the system (Relay Chain or system parachain).
pub struct ConcreteAssetFromSystem<AssetLocation>(PhantomData<AssetLocation>); pub struct ConcreteAssetFromSystem<AssetLocation>(PhantomData<AssetLocation>);
impl<AssetLocation: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation> impl<AssetLocation: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation>
@@ -25,8 +25,11 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain",
polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" }
xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false}
pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false}
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false}
rococo-runtime = { path = "../../../../../../polkadot/runtime/rococo", default-features = false }
# Cumulus # Cumulus
asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false }
parachains-common = { path = "../../../../common" } parachains-common = { path = "../../../../common" }
asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" } asset-hub-rococo-runtime = { path = "../../../../runtimes/assets/asset-hub-rococo" }
@@ -47,5 +50,7 @@ runtime-benchmarks = [
"parachains-common/runtime-benchmarks", "parachains-common/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks",
"rococo-runtime/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
] ]
@@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub use asset_test_utils::xcm_helpers;
pub use codec::Encode; pub use codec::Encode;
pub use frame_support::{ pub use frame_support::{
assert_err, assert_ok, assert_err, assert_ok,
@@ -14,6 +14,8 @@
// limitations under the License. // limitations under the License.
use crate::*; use crate::*;
use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig;
use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) { fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
@@ -182,10 +184,16 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() {
test.set_dispatchable::<Rococo>(relay_limited_reserve_transfer_assets); test.set_dispatchable::<Rococo>(relay_limited_reserve_transfer_assets);
test.assert(); test.assert();
let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after);
} }
@@ -244,7 +252,13 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after);
} }
@@ -306,7 +320,13 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve
// transfers // transfers
} }
@@ -338,7 +358,13 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve
// transfers // transfers
} }
@@ -14,6 +14,8 @@
// limitations under the License. // limitations under the License.
use crate::*; use crate::*;
use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig;
use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) { fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
@@ -171,11 +173,17 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() {
test.set_dispatchable::<Rococo>(relay_limited_teleport_assets); test.set_dispatchable::<Rococo>(relay_limited_teleport_assets);
test.assert(); test.assert();
let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -212,8 +220,14 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -247,8 +261,14 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance does not change // Receiver's balance does not change
assert_eq!(receiver_balance_after, receiver_balance_before); assert_eq!(receiver_balance_after, receiver_balance_before);
} }
@@ -274,11 +294,17 @@ fn teleport_native_assets_from_relay_to_system_para_works() {
test.set_dispatchable::<Rococo>(relay_teleport_assets); test.set_dispatchable::<Rococo>(relay_teleport_assets);
test.assert(); test.assert();
let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -315,8 +341,14 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -347,11 +379,17 @@ fn teleport_native_assets_from_system_para_to_relay_fails() {
test.set_dispatchable::<AssetHubRococo>(system_para_teleport_assets); test.set_dispatchable::<AssetHubRococo>(system_para_teleport_assets);
test.assert(); test.assert();
let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance does not change // Receiver's balance does not change
assert_eq!(receiver_balance_after, receiver_balance_before); assert_eq!(receiver_balance_after, receiver_balance_before);
} }
@@ -359,11 +397,12 @@ fn teleport_native_assets_from_system_para_to_relay_fails() {
#[test] #[test]
fn teleport_to_other_system_parachains_works() { fn teleport_to_other_system_parachains_works() {
let amount = ASSET_HUB_ROCOCO_ED * 100; let amount = ASSET_HUB_ROCOCO_ED * 100;
let native_asset: VersionedMultiAssets = (Parent, amount).into(); let native_asset: MultiAssets = (Parent, amount).into();
test_parachain_is_trusted_teleporter!( test_parachain_is_trusted_teleporter!(
AssetHubRococo, // Origin AssetHubRococo, // Origin
vec![BridgeHubRococo], // Destinations AssetHubRococoXcmConfig, // XCM Configuration
vec![BridgeHubRococo], // Destinations
(native_asset, amount) (native_asset, amount)
); );
} }
@@ -30,10 +30,13 @@ xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", defaul
xcm-builder = { package = "staging-xcm-builder", path = "../../../../../../polkadot/xcm/xcm-builder", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../../../../polkadot/xcm/xcm-builder", default-features = false}
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false}
pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false}
westend-runtime = { path = "../../../../../../polkadot/runtime/westend", default-features = false }
westend-runtime-constants = { path = "../../../../../../polkadot/runtime/westend/constants", default-features = false }
# Cumulus # Cumulus
parachains-common = { path = "../../../../common" } parachains-common = { path = "../../../../common" }
asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" } asset-hub-westend-runtime = { path = "../../../../runtimes/assets/asset-hub-westend" }
asset-test-utils = { path = "../../../../runtimes/assets/test-utils", default-features = false }
cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../pallets/dmp-queue" }
cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../pallets/parachain-system" }
@@ -59,6 +62,7 @@ runtime-benchmarks = [
"polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"westend-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks", "xcm-executor/runtime-benchmarks",
] ]
@@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub use asset_test_utils::xcm_helpers;
pub use codec::Encode; pub use codec::Encode;
pub use frame_support::{ pub use frame_support::{
assert_err, assert_ok, assert_err, assert_ok,
@@ -14,6 +14,8 @@
// limitations under the License. // limitations under the License.
use crate::*; use crate::*;
use asset_hub_westend_runtime::xcm_config::XcmConfig;
use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) { fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Westend as Chain>::RuntimeEvent; type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
@@ -179,10 +181,16 @@ fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() {
test.set_dispatchable::<Westend>(relay_limited_reserve_transfer_assets); test.set_dispatchable::<Westend>(relay_limited_reserve_transfer_assets);
test.assert(); test.assert();
let delivery_fees = Westend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<WestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after);
} }
@@ -238,10 +246,16 @@ fn reserve_transfer_native_asset_from_relay_to_system_para_fails() {
test.set_dispatchable::<Westend>(relay_reserve_transfer_assets); test.set_dispatchable::<Westend>(relay_reserve_transfer_assets);
test.assert(); test.assert();
let delivery_fees = Westend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<WestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after); assert_eq!(receiver_balance_before, receiver_balance_after);
} }
@@ -303,7 +317,17 @@ fn limited_reserve_transfer_native_asset_from_system_para_to_para() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<<XcmConfig as xcm_executor::Config>::XcmSender>(
test.args.assets.clone(),
0,
test.args.weight_limit,
test.args.beneficiary,
test.args.dest,
)
});
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve
// transfers // transfers
} }
@@ -335,7 +359,17 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<<XcmConfig as xcm_executor::Config>::XcmSender>(
test.args.assets.clone(),
0,
test.args.weight_limit,
test.args.beneficiary,
test.args.dest,
)
});
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve
// transfers // transfers
} }
@@ -16,6 +16,8 @@
#![allow(dead_code)] // <https://github.com/paritytech/cumulus/issues/3027> #![allow(dead_code)] // <https://github.com/paritytech/cumulus/issues/3027>
use crate::*; use crate::*;
use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig;
use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) { fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Westend as Chain>::RuntimeEvent; type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
@@ -173,11 +175,17 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() {
test.set_dispatchable::<Westend>(relay_limited_teleport_assets); test.set_dispatchable::<Westend>(relay_limited_teleport_assets);
test.assert(); test.assert();
let delivery_fees = Westend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<WestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -214,8 +222,14 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubWestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -249,8 +263,14 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() {
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubWestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance does not change // Receiver's balance does not change
assert_eq!(receiver_balance_after, receiver_balance_before); assert_eq!(receiver_balance_after, receiver_balance_before);
} }
@@ -276,11 +296,17 @@ fn teleport_native_assets_from_relay_to_system_para_works() {
test.set_dispatchable::<Westend>(relay_teleport_assets); test.set_dispatchable::<Westend>(relay_teleport_assets);
test.assert(); test.assert();
let delivery_fees = Westend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<WestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -314,11 +340,17 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() {
test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets); test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets);
test.assert(); test.assert();
let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubWestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased // Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before); assert!(receiver_balance_after > receiver_balance_before);
} }
@@ -349,11 +381,17 @@ fn teleport_native_assets_from_system_para_to_relay_fails() {
test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets); test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets);
test.assert(); test.assert();
let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubWestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced // Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance does not change // Receiver's balance does not change
assert_eq!(receiver_balance_after, receiver_balance_before); assert_eq!(receiver_balance_after, receiver_balance_before);
} }
@@ -19,13 +19,16 @@ polkadot-parachain-primitives = { path = "../../../../../../polkadot/parachain",
polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" } polkadot-runtime-parachains = { path = "../../../../../../polkadot/runtime/parachains" }
xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../../polkadot/xcm", default-features = false}
pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm = { path = "../../../../../../polkadot/xcm/pallet-xcm", default-features = false}
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", default-features = false}
# Cumulus # Cumulus
asset-test-utils = { path = "../../../../../parachains/runtimes/assets/test-utils", default-features = false }
parachains-common = { path = "../../../../common" } parachains-common = { path = "../../../../common" }
cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false} cumulus-pallet-xcmp-queue = { path = "../../../../../pallets/xcmp-queue", default-features = false}
cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false} cumulus-pallet-dmp-queue = { path = "../../../../../pallets/dmp-queue", default-features = false}
pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false} pallet-bridge-messages = { path = "../../../../../../bridges/modules/messages", default-features = false}
bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false} bp-messages = { path = "../../../../../../bridges/primitives/messages", default-features = false}
bridge-hub-rococo-runtime = { path = "../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false }
# Local # Local
xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false} xcm-emulator = { path = "../../../../../xcm/xcm-emulator", default-features = false}
@@ -14,14 +14,16 @@
// limitations under the License. // limitations under the License.
use crate::*; use crate::*;
use bridge_hub_rococo_runtime::xcm_config::XcmConfig;
#[test] #[test]
fn teleport_to_other_system_parachains_works() { fn teleport_to_other_system_parachains_works() {
let amount = BRIDGE_HUB_ROCOCO_ED * 100; let amount = BRIDGE_HUB_ROCOCO_ED * 100;
let native_asset: VersionedMultiAssets = (Parent, amount).into(); let native_asset: MultiAssets = (Parent, amount).into();
test_parachain_is_trusted_teleporter!( test_parachain_is_trusted_teleporter!(
BridgeHubRococo, // Origin BridgeHubRococo, // Origin
XcmConfig, // XCM configuration
vec![AssetHubRococo], // Destinations vec![AssetHubRococo], // Destinations
(native_asset, amount) (native_asset, amount)
); );
@@ -15,7 +15,7 @@
#[macro_export] #[macro_export]
macro_rules! test_parachain_is_trusted_teleporter { macro_rules! test_parachain_is_trusted_teleporter {
( $sender_para:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { ( $sender_para:ty, $sender_xcm_config:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => {
$crate::paste::paste! { $crate::paste::paste! {
// init Origin variables // init Origin variables
let sender = [<$sender_para Sender>]::get(); let sender = [<$sender_para Sender>]::get();
@@ -32,19 +32,22 @@ macro_rules! test_parachain_is_trusted_teleporter {
let para_receiver_balance_before = let para_receiver_balance_before =
<$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free;
let para_destination = let para_destination =
<$sender_para>::sibling_location_of(<$receiver_para>::para_id()).into(); <$sender_para>::sibling_location_of(<$receiver_para>::para_id());
let beneficiary = let beneficiary: MultiLocation =
$crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); $crate::AccountId32 { network: None, id: receiver.clone().into() }.into();
dbg!(&origin);
dbg!(&para_destination);
// Send XCM message from Origin Parachain // Send XCM message from Origin Parachain
// We are only testing the limited teleport version, which should be ok since success will // We are only testing the limited teleport version, which should be ok since success will
// depend only on a proper `XcmConfig` at destination. // depend only on a proper `XcmConfig` at destination.
<$sender_para>::execute_with(|| { <$sender_para>::execute_with(|| {
assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets( assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets(
origin.clone(), origin.clone(),
bx!(para_destination), bx!(para_destination.into()),
bx!(beneficiary), bx!(beneficiary.into()),
bx!($assets.clone()), bx!($assets.clone().into()),
fee_asset_item, fee_asset_item,
weight_limit.clone(), weight_limit.clone(),
)); ));
@@ -89,8 +92,13 @@ macro_rules! test_parachain_is_trusted_teleporter {
<$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free;
let para_receiver_balance_after = let para_receiver_balance_after =
<$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free;
let delivery_fees = <$sender_para>::execute_with(|| {
asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::<
<$sender_xcm_config as xcm_executor::Config>::XcmSender,
>($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination)
});
assert_eq!(para_sender_balance_before - $amount, para_sender_balance_after); assert_eq!(para_sender_balance_before - $amount - delivery_fees, para_sender_balance_after);
assert!(para_receiver_balance_after > para_receiver_balance_before); assert!(para_receiver_balance_after > para_receiver_balance_before);
// Update sender balance // Update sender balance
@@ -14,14 +14,7 @@
// limitations under the License. // limitations under the License.
use parachains_common::AccountId; use parachains_common::AccountId;
use xcm::{ use xcm::{prelude::*, DoubleEncoded};
prelude::{
AccountId32, All, BuyExecution, DepositAsset, MultiAsset, MultiAssets, MultiLocation,
OriginKind, RefundSurplus, Transact, UnpaidExecution, VersionedXcm, Weight, WeightLimit,
WithdrawAsset, Xcm, X1,
},
DoubleEncoded,
};
/// Helper method to build a XCM with a `Transact` instruction and paying for its execution /// Helper method to build a XCM with a `Transact` instruction and paying for its execution
pub fn xcm_transact_paid_execution( pub fn xcm_transact_paid_execution(
@@ -34,6 +34,8 @@ use assets_common::{
AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId,
}; };
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{ use sp_runtime::{
@@ -88,7 +90,7 @@ pub use sp_runtime::BuildStorage;
// Polkadot imports // Polkadot imports
use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::BodyId; use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
use crate::xcm_config::{ use crate::xcm_config::{
@@ -645,7 +647,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
>; >;
type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -1211,9 +1213,21 @@ impl_runtime_apis! {
use xcm_config::{KsmLocation, MaxAssetsIntoHolding}; use xcm_config::{KsmLocation, MaxAssetsIntoHolding};
use pallet_xcm_benchmarks::asset_instance_from; use pallet_xcm_benchmarks::asset_instance_from;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
KsmLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(KsmLocation::get()) Ok(KsmLocation::get())
} }
@@ -1269,6 +1283,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -16,9 +16,9 @@
use super::{ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo, AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo,
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
}; };
use crate::ForeignAssets; use crate::{ForeignAssets, CENTS};
use assets_common::{ use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
matching::{FromSiblingParachain, IsForeignConcreteAsset}, matching::{FromSiblingParachain, IsForeignConcreteAsset},
@@ -34,6 +34,7 @@ use parachains_common::{
xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem},
}; };
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use sp_runtime::traits::ConvertInto; use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
@@ -532,11 +533,21 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(KsmLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -66,6 +66,8 @@ use assets_common::{
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId, foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
}; };
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{ use sp_runtime::{
@@ -118,7 +120,7 @@ pub use sp_runtime::BuildStorage;
// Polkadot imports // Polkadot imports
use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::BodyId; use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
use crate::xcm_config::ForeignCreatorsSovereignAccountOf; use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
@@ -581,7 +583,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
EnsureXcm<IsVoiceOfBody<FellowshipLocation, FellowsBodyId>>, EnsureXcm<IsVoiceOfBody<FellowshipLocation, FellowsBodyId>>,
>; >;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -1090,9 +1092,21 @@ impl_runtime_apis! {
use xcm_config::{DotLocation, MaxAssetsIntoHolding}; use xcm_config::{DotLocation, MaxAssetsIntoHolding};
use pallet_xcm_benchmarks::asset_instance_from; use pallet_xcm_benchmarks::asset_instance_from;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
xcm_config::DotLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(DotLocation::get()) Ok(DotLocation::get())
} }
@@ -1148,6 +1162,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -16,7 +16,7 @@
use super::{ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets, AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets,
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, CENTS,
}; };
use assets_common::matching::{FromSiblingParachain, IsForeignConcreteAsset}; use assets_common::matching::{FromSiblingParachain, IsForeignConcreteAsset};
use frame_support::{ use frame_support::{
@@ -30,6 +30,7 @@ use parachains_common::{
xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem},
}; };
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use sp_runtime::traits::ConvertInto; use sp_runtime::traits::ConvertInto;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
@@ -456,11 +457,21 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(DotLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -55,6 +55,7 @@ sp-weights = { path = "../../../../../substrate/primitives/weights", default-fea
primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "scale-info", "num-traits"] } primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "scale-info", "num-traits"] }
# Polkadot # Polkadot
rococo-runtime = { path = "../../../../../polkadot/runtime/rococo", default-features = false }
rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false} rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false}
pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false}
pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true } pallet-xcm-benchmarks = { path = "../../../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false, optional = true }
@@ -130,6 +131,7 @@ runtime-benchmarks = [
"parachains-common/runtime-benchmarks", "parachains-common/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks",
"rococo-runtime/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks", "xcm-executor/runtime-benchmarks",
@@ -165,6 +167,7 @@ try-runtime = [
"pallet-xcm/try-runtime", "pallet-xcm/try-runtime",
"parachain-info/try-runtime", "parachain-info/try-runtime",
"polkadot-runtime-common/try-runtime", "polkadot-runtime-common/try-runtime",
"rococo-runtime/try-runtime",
"sp-runtime/try-runtime", "sp-runtime/try-runtime",
] ]
std = [ std = [
@@ -218,6 +221,7 @@ std = [
"polkadot-parachain-primitives/std", "polkadot-parachain-primitives/std",
"polkadot-runtime-common/std", "polkadot-runtime-common/std",
"rococo-runtime-constants/std", "rococo-runtime-constants/std",
"rococo-runtime/std",
"scale-info/std", "scale-info/std",
"sp-api/std", "sp-api/std",
"sp-block-builder/std", "sp-block-builder/std",
@@ -93,7 +93,7 @@ pub use sp_runtime::BuildStorage;
// Polkadot imports // Polkadot imports
use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::BodyId; use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
use crate::xcm_config::{ use crate::xcm_config::{
@@ -636,6 +636,20 @@ impl parachain_info::Config for Runtime {}
impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(xcm_config::TokenLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
TransactionByteFee,
XcmpQueue,
>;
impl cumulus_pallet_xcmp_queue::Config for Runtime { impl cumulus_pallet_xcmp_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
@@ -645,7 +659,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -1315,9 +1329,21 @@ impl_runtime_apis! {
use xcm_config::{TokenLocation, MaxAssetsIntoHolding}; use xcm_config::{TokenLocation, MaxAssetsIntoHolding};
use pallet_xcm_benchmarks::asset_instance_from; use pallet_xcm_benchmarks::asset_instance_from;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
TokenLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(TokenLocation::get()) Ok(TokenLocation::get())
} }
@@ -1373,6 +1399,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -14,10 +14,11 @@
// limitations under the License. // limitations under the License.
use super::{ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets, AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee,
ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm,
RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, ToRococoXcmRouter, ToWococoXcmRouter, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin,
TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, ToRococoXcmRouter, ToWococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance,
WeightToFee, XcmpQueue,
}; };
use assets_common::{ use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation, local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
@@ -31,10 +32,17 @@ use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use parachains_common::{ use parachains_common::{
impls::ToStakingPot, impls::ToStakingPot,
xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, xcm_config::{
AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem,
RelayOrOtherSystemParachains,
},
TREASURY_PALLET_ID,
}; };
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use sp_runtime::traits::ConvertInto; use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use rococo_runtime::Treasury as RococoTreasury;
use rococo_runtime_constants::system_parachain::SystemParachains;
use sp_runtime::traits::{AccountIdConversion, ConvertInto};
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllAssets, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllAssets, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -46,6 +54,7 @@ use xcm_builder::{
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeesToAccount,
}; };
use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -67,6 +76,7 @@ parameter_types! {
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into(); PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub CheckingAccount: AccountId = PolkadotXcm::check_account();
pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent();
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
} }
/// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. /// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`.
@@ -521,6 +531,23 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger =
ForeignAssetsInstance, ForeignAssetsInstance,
>; >;
parameter_types! {
pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(<RococoTreasury as PalletInfoAccess>::index() as u8)).into();
}
pub struct RelayTreasury;
impl Contains<MultiLocation> for RelayTreasury {
fn contains(location: &MultiLocation) -> bool {
let relay_treasury_location = RelayTreasuryLocation::get();
*location == relay_treasury_location
}
}
/// Locations that will not be charged fees in the executor,
/// either execution or delivery.
/// We only waive fees for system functions, which these locations represent.
pub type WaivedLocations = (RelayOrOtherSystemParachains<SystemParachains, Runtime>, RelayTreasury);
/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// Cases where a remote origin is accepted as trusted Teleporter for a given asset:
/// ///
/// - ROC with the parent Relay Chain and sibling system parachains; and /// - ROC with the parent Relay Chain and sibling system parachains; and
@@ -588,8 +615,7 @@ impl xcm_executor::Config for XcmConfig {
type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type AssetLocker = (); type AssetLocker = ();
type AssetExchanger = (); type AssetExchanger = ();
// TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot-sdk/pull/1234) merged type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
type FeeManager = ();
type MessageExporter = (); type MessageExporter = ();
type UniversalAliases = type UniversalAliases =
(bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases); (bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases);
@@ -602,10 +628,13 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// For routing XCM messages which do not cross local consensus boundary. /// For routing XCM messages which do not cross local consensus boundary.
type LocalXcmRouter = ( type LocalXcmRouter = (
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
); );
@@ -60,6 +60,7 @@ polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", d
polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false}
polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false}
westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false} westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/constants", default-features = false}
westend-runtime = { path = "../../../../../polkadot/runtime/westend", default-features = false }
xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false}
xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false}
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false}
@@ -116,6 +117,7 @@ runtime-benchmarks = [
"polkadot-parachain-primitives/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"westend-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks", "xcm-executor/runtime-benchmarks",
] ]
@@ -149,6 +151,7 @@ try-runtime = [
"parachain-info/try-runtime", "parachain-info/try-runtime",
"polkadot-runtime-common/try-runtime", "polkadot-runtime-common/try-runtime",
"sp-runtime/try-runtime", "sp-runtime/try-runtime",
"westend-runtime/try-runtime",
] ]
std = [ std = [
"assets-common/std", "assets-common/std",
@@ -210,6 +213,7 @@ std = [
"sp-version/std", "sp-version/std",
"substrate-wasm-builder", "substrate-wasm-builder",
"westend-runtime-constants/std", "westend-runtime-constants/std",
"westend-runtime/std",
"xcm-builder/std", "xcm-builder/std",
"xcm-executor/std", "xcm-executor/std",
"xcm/std", "xcm/std",
@@ -88,6 +88,7 @@ use assets_common::{
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId, foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
}; };
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
use crate::xcm_config::ForeignCreatorsSovereignAccountOf; use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
@@ -604,6 +605,20 @@ impl parachain_info::Config for Runtime {}
impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(xcm_config::WestendLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
TransactionByteFee,
XcmpQueue,
>;
impl cumulus_pallet_xcmp_queue::Config for Runtime { impl cumulus_pallet_xcmp_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
@@ -613,7 +628,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -1262,9 +1277,21 @@ impl_runtime_apis! {
use xcm_config::{MaxAssetsIntoHolding, WestendLocation}; use xcm_config::{MaxAssetsIntoHolding, WestendLocation};
use pallet_xcm_benchmarks::asset_instance_from; use pallet_xcm_benchmarks::asset_instance_from;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
WestendLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(WestendLocation::get()) Ok(WestendLocation::get())
} }
@@ -1320,6 +1347,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -1421,7 +1449,6 @@ pub mod migrations {
}; };
use parachains_common::impls::AccountIdOf; use parachains_common::impls::AccountIdOf;
use sp_runtime::{traits::StaticLookup, Saturating}; use sp_runtime::{traits::StaticLookup, Saturating};
use xcm::latest::prelude::*;
/// Temporary migration because of bug with native asset, it can be removed once applied on /// Temporary migration because of bug with native asset, it can be removed once applied on
/// `AssetHubWestend`. Migrates pools with `MultiLocation { parents: 0, interior: Here }` to /// `AssetHubWestend`. Migrates pools with `MultiLocation { parents: 0, interior: Here }` to
@@ -14,9 +14,10 @@
// limitations under the License. // limitations under the License.
use super::{ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ParachainInfo, AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee,
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue, RuntimeEvent, RuntimeOrigin, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee,
XcmpQueue,
}; };
use crate::ForeignAssets; use crate::ForeignAssets;
use assets_common::{ use assets_common::{
@@ -31,10 +32,17 @@ use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use parachains_common::{ use parachains_common::{
impls::ToStakingPot, impls::ToStakingPot,
xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, xcm_config::{
AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem,
RelayOrOtherSystemParachains,
},
TREASURY_PALLET_ID,
}; };
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use sp_runtime::traits::ConvertInto; use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use sp_runtime::traits::{AccountIdConversion, ConvertInto};
use westend_runtime::Treasury as WestendTreasury;
use westend_runtime_constants::system_parachain;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -45,6 +53,7 @@ use xcm_builder::{
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeesToAccount,
}; };
use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -65,6 +74,7 @@ parameter_types! {
pub PoolAssetsPalletLocation: MultiLocation = pub PoolAssetsPalletLocation: MultiLocation =
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into(); PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub CheckingAccount: AccountId = PolkadotXcm::check_account();
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
} }
/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
@@ -482,6 +492,36 @@ pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentia
TrustBackedAssetsInstance, TrustBackedAssetsInstance,
>; >;
match_types! {
pub type SystemParachains: impl Contains<MultiLocation> = {
MultiLocation {
parents: 1,
interior: X1(Parachain(
system_parachain::ASSET_HUB_ID |
system_parachain::COLLECTIVES_ID |
system_parachain::BRIDGE_HUB_ID
)),
}
};
}
parameter_types! {
pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(<WestendTreasury as PalletInfoAccess>::index() as u8)).into();
}
pub struct RelayTreasury;
impl Contains<MultiLocation> for RelayTreasury {
fn contains(location: &MultiLocation) -> bool {
let relay_treasury_location = RelayTreasuryLocation::get();
*location == relay_treasury_location
}
}
/// Locations that will not be charged fees in the executor,
/// either execution or delivery.
/// We only waive fees for system functions, which these locations represent.
pub type WaivedLocations = (RelayOrOtherSystemParachains<SystemParachains, Runtime>, RelayTreasury);
/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// Cases where a remote origin is accepted as trusted Teleporter for a given asset:
/// ///
/// - WND with the parent Relay Chain and sibling system parachains; and /// - WND with the parent Relay Chain and sibling system parachains; and
@@ -531,7 +571,7 @@ impl xcm_executor::Config for XcmConfig {
type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type AssetLocker = (); type AssetLocker = ();
type AssetExchanger = (); type AssetExchanger = ();
type FeeManager = (); type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
type MessageExporter = (); type MessageExporter = ();
type UniversalAliases = Nothing; type UniversalAliases = Nothing;
type CallDispatcher = WithOriginFilter<SafeCallFilter>; type CallDispatcher = WithOriginFilter<SafeCallFilter>;
@@ -542,11 +582,14 @@ impl xcm_executor::Config for XcmConfig {
/// Local origins on this chain are allowed to dispatch XCM sends/executions. /// Local origins on this chain are allowed to dispatch XCM sends/executions.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -34,11 +34,11 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features =
parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false } parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false }
# Polkadot # Polkadot
xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false }
xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false }
pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false }
polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false }
# Bridges # Bridges
pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false }
@@ -18,4 +18,5 @@
pub mod test_cases; pub mod test_cases;
pub mod test_cases_over_bridge; pub mod test_cases_over_bridge;
pub mod xcm_helpers;
pub use parachains_runtimes_test_utils::*; pub use parachains_runtimes_test_utils::*;
@@ -15,10 +15,13 @@
//! Module contains predefined test-case scenarios for `Runtime` with various assets. //! Module contains predefined test-case scenarios for `Runtime` with various assets.
use super::xcm_helpers;
use codec::Encode; use codec::Encode;
use frame_support::{ use frame_support::{
assert_noop, assert_ok, assert_noop, assert_ok,
traits::{fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait}, traits::{
fungible::Mutate, fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait,
},
weights::Weight, weights::Weight,
}; };
use frame_system::pallet_prelude::BlockNumberFor; use frame_system::pallet_prelude::BlockNumberFor;
@@ -175,6 +178,21 @@ pub fn teleports_for_native_asset_works<
target_account_balance_before_teleport - existential_deposit target_account_balance_before_teleport - existential_deposit
); );
// Mint funds into account to ensure it has enough balance to pay delivery fees
let delivery_fees =
xcm_helpers::transfer_assets_delivery_fees::<XcmConfig::XcmSender>(
(native_asset_id, native_asset_to_teleport_away.into()).into(),
0,
Unlimited,
dest_beneficiary,
dest,
);
<pallet_balances::Pallet<Runtime>>::mint_into(
&target_account,
delivery_fees.into(),
)
.unwrap();
assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>( assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
RuntimeHelper::<Runtime>::origin_of(target_account.clone()), RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
dest, dest,
@@ -184,6 +202,7 @@ pub fn teleports_for_native_asset_works<
included_head.clone(), included_head.clone(),
&alice, &alice,
)); ));
// check balances // check balances
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
@@ -232,10 +251,21 @@ pub fn teleports_for_native_asset_works<
&alice, &alice,
)); ));
let delivery_fees =
xcm_helpers::transfer_assets_delivery_fees::<XcmConfig::XcmSender>(
(native_asset_id, native_asset_to_teleport_away.into()).into(),
0,
Unlimited,
dest_beneficiary,
dest,
);
// check balances // check balances
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
target_account_balance_before_teleport - native_asset_to_teleport_away target_account_balance_before_teleport -
native_asset_to_teleport_away -
delivery_fees.into()
); );
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()), <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
@@ -370,7 +400,7 @@ pub fn teleports_for_foreign_assets_works<
fun: Fungible(buy_execution_fee_amount), fun: Fungible(buy_execution_fee_amount),
}; };
let teleported_foreign_asset_amount = 10000000000000; let teleported_foreign_asset_amount = 10_000_000_000_000;
let runtime_para_id = 1000; let runtime_para_id = 1000;
ExtBuilder::<Runtime>::default() ExtBuilder::<Runtime>::default()
.with_collators(collator_session_keys.collators()) .with_collators(collator_session_keys.collators())
@@ -400,11 +430,11 @@ pub fn teleports_for_foreign_assets_works<
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
existential_deposit existential_deposit
); );
// check `CheckingAccount` before
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()), <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
existential_deposit existential_deposit
); );
// check `CheckingAccount` before
assert_eq!( assert_eq!(
<pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance( <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
foreign_asset_id_multilocation.into(), foreign_asset_id_multilocation.into(),
@@ -540,6 +570,21 @@ pub fn teleports_for_foreign_assets_works<
.into() .into()
); );
// Make sure the target account has enough native asset to pay for delivery fees
let delivery_fees =
xcm_helpers::transfer_assets_delivery_fees::<XcmConfig::XcmSender>(
(foreign_asset_id_multilocation, asset_to_teleport_away).into(),
0,
Unlimited,
dest_beneficiary,
dest,
);
<pallet_balances::Pallet<Runtime>>::mint_into(
&target_account,
delivery_fees.into(),
)
.unwrap();
assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>( assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
RuntimeHelper::<Runtime>::origin_of(target_account.clone()), RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
dest, dest,
@@ -20,7 +20,9 @@ use codec::Encode;
use cumulus_primitives_core::XcmpMessageSource; use cumulus_primitives_core::XcmpMessageSource;
use frame_support::{ use frame_support::{
assert_ok, assert_ok,
traits::{Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError}, traits::{
fungible::Mutate, Currency, OnFinalize, OnInitialize, OriginTrait, ProcessMessageError,
},
}; };
use frame_system::pallet_prelude::BlockNumberFor; use frame_system::pallet_prelude::BlockNumberFor;
use parachains_common::{AccountId, Balance}; use parachains_common::{AccountId, Balance};
@@ -164,6 +166,12 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
}), }),
}; };
// Make sure sender has enough funds for paying delivery fees
// TODO: Get this fee via weighing the corresponding message
let delivery_fees = 1324039894;
<pallet_balances::Pallet<Runtime>>::mint_into(&alice_account, delivery_fees.into())
.unwrap();
// do pallet_xcm call reserve transfer // do pallet_xcm call reserve transfer
assert_ok!(<pallet_xcm::Pallet<Runtime>>::limited_reserve_transfer_assets( assert_ok!(<pallet_xcm::Pallet<Runtime>>::limited_reserve_transfer_assets(
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()), RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()),
@@ -0,0 +1,108 @@
// Copyright 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 <http://www.gnu.org/licenses/>.
//! Helpers for calculating XCM delivery fees.
use xcm::latest::prelude::*;
/// Returns the delivery fees amount for pallet xcm's `teleport_assets` and
/// `reserve_transfer_assets` extrinsics.
/// Because it returns only a `u128`, it assumes delivery fees are only paid
/// in one asset and that asset is known.
pub fn transfer_assets_delivery_fees<S: SendXcm>(
assets: MultiAssets,
fee_asset_item: u32,
weight_limit: WeightLimit,
beneficiary: MultiLocation,
destination: MultiLocation,
) -> u128 {
let message = teleport_assets_dummy_message(assets, fee_asset_item, weight_limit, beneficiary);
get_fungible_delivery_fees::<S>(destination, message)
}
/// Returns the delivery fees amount for a query response as a result of the execution
/// of a `ExpectError` instruction with no error.
pub fn query_response_delivery_fees<S: SendXcm>(querier: MultiLocation) -> u128 {
// Message to calculate delivery fees, it's encoded size is what's important.
// This message reports that there was no error, if an error is reported, the encoded size would
// be different.
let message = Xcm(vec![
SetFeesMode { jit_withdraw: true },
QueryResponse {
query_id: 0, // Dummy query id
response: Response::ExecutionResult(None),
max_weight: Weight::zero(),
querier: Some(querier),
},
SetTopic([0u8; 32]), // Dummy topic
]);
get_fungible_delivery_fees::<S>(querier, message)
}
/// Returns the delivery fees amount for the execution of `PayOverXcm`
pub fn pay_over_xcm_delivery_fees<S: SendXcm>(
interior: Junctions,
destination: MultiLocation,
beneficiary: MultiLocation,
asset: MultiAsset,
) -> u128 {
// This is a dummy message.
// The encoded size is all that matters for delivery fees.
let message = Xcm(vec![
DescendOrigin(interior),
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
SetAppendix(Xcm(vec![
SetFeesMode { jit_withdraw: true },
ReportError(QueryResponseInfo { destination, query_id: 0, max_weight: Weight::zero() }),
])),
TransferAsset { beneficiary, assets: vec![asset].into() },
]);
get_fungible_delivery_fees::<S>(destination, message)
}
/// Approximates the actual message sent by the teleport extrinsic.
/// The assets are not reanchored and the topic is a dummy one.
/// However, it should have the same encoded size, which is what matters for delivery fees.
/// Also has same encoded size as the one created by the reserve transfer assets extrinsic.
fn teleport_assets_dummy_message(
assets: MultiAssets,
fee_asset_item: u32,
weight_limit: WeightLimit,
beneficiary: MultiLocation,
) -> Xcm<()> {
Xcm(vec![
ReceiveTeleportedAsset(assets.clone()), // Same encoded size as `ReserveAssetDeposited`
ClearOrigin,
BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit },
DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary },
SetTopic([0u8; 32]), // Dummy topic
])
}
/// Given a message, a sender, and a destination, it returns the delivery fees
fn get_fungible_delivery_fees<S: SendXcm>(destination: MultiLocation, message: Xcm<()>) -> u128 {
let Ok((_, delivery_fees)) = validate_send::<S>(destination, message) else {
unreachable!("message can be sent; qed")
};
if let Some(delivery_fee) = delivery_fees.inner().first() {
let Fungible(delivery_fee_amount) = delivery_fee.fun else {
unreachable!("asset is fungible; qed");
};
delivery_fee_amount
} else {
0
}
}
@@ -26,6 +26,8 @@ mod weights;
pub mod xcm_config; pub mod xcm_config;
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{ use sp_runtime::{
@@ -75,7 +77,7 @@ use parachains_common::{
}; };
// XCM Imports // XCM Imports
use xcm::latest::prelude::BodyId; use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
/// The address format for describing accounts. /// The address format for describing accounts.
@@ -314,7 +316,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = RootOrFellows; type ControllerOrigin = RootOrFellows;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -671,9 +673,21 @@ impl_runtime_apis! {
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::KsmRelayLocation; use xcm_config::KsmRelayLocation;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
xcm_config::KsmRelayLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(KsmRelayLocation::get()) Ok(KsmRelayLocation::get())
} }
@@ -714,6 +728,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -16,7 +16,8 @@
use super::{ use super::{
AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm,
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue,
CENTS,
}; };
use frame_support::{ use frame_support::{
match_types, parameter_types, match_types, parameter_types,
@@ -26,6 +27,7 @@ use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem};
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -220,11 +222,21 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(KsmRelayLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -26,6 +26,8 @@ mod weights;
pub mod xcm_config; pub mod xcm_config;
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{ use sp_runtime::{
@@ -75,7 +77,7 @@ use parachains_common::{
HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
}; };
// XCM Imports // XCM Imports
use xcm::latest::prelude::BodyId; use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
/// The address format for describing accounts. /// The address format for describing accounts.
@@ -314,7 +316,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = RootOrFellows; type ControllerOrigin = RootOrFellows;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -671,9 +673,21 @@ impl_runtime_apis! {
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::DotRelayLocation; use xcm_config::DotRelayLocation;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
xcm_config::DotRelayLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(DotRelayLocation::get()) Ok(DotRelayLocation::get())
} }
@@ -714,6 +728,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -16,7 +16,8 @@
use super::{ use super::{
AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm,
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue,
CENTS,
}; };
use frame_support::{ use frame_support::{
match_types, parameter_types, match_types, parameter_types,
@@ -26,6 +27,7 @@ use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem};
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -224,11 +226,21 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(DotRelayLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -75,6 +75,7 @@ use bp_runtime::HeaderId;
pub use sp_runtime::BuildStorage; pub use sp_runtime::BuildStorage;
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::prelude::*;
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
@@ -362,6 +363,20 @@ impl parachain_info::Config for Runtime {}
impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(xcm_config::TokenLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
TransactionByteFee,
XcmpQueue,
>;
impl cumulus_pallet_xcmp_queue::Config for Runtime { impl cumulus_pallet_xcmp_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
@@ -371,7 +386,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -1014,9 +1029,21 @@ impl_runtime_apis! {
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::TokenLocation; use xcm_config::TokenLocation;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
TokenLocation::get(),
ExistentialDeposit::get()
).into());
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationToAccountId; type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(TokenLocation::get()) Ok(TokenLocation::get())
} }
@@ -1057,6 +1084,7 @@ impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -15,10 +15,10 @@
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. // along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use super::{ use super::{
AccountId, AllPalletsWithSystem, Balances, BridgeGrandpaRococoInstance, AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, BridgeGrandpaRococoInstance,
BridgeGrandpaWococoInstance, DeliveryRewardInBalance, ParachainInfo, ParachainSystem, BridgeGrandpaWococoInstance, DeliveryRewardInBalance, FeeAssetId, ParachainInfo,
PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall,
RuntimeOrigin, WeightToFee, XcmpQueue, RuntimeEvent, RuntimeFlavor, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue,
}; };
use crate::{ use crate::{
bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter, bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter,
@@ -30,9 +30,16 @@ use frame_support::{
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use parachains_common::{
impls::ToStakingPot,
xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains},
TREASURY_PALLET_ID,
};
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use rococo_runtime_constants::system_parachain::SystemParachains;
use sp_core::Get; use sp_core::Get;
use sp_runtime::traits::AccountIdConversion;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -41,6 +48,7 @@ use xcm_builder::{
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeesToAccount,
}; };
use xcm_executor::{ use xcm_executor::{
traits::{ExportXcm, WithOriginFilter}, traits::{ExportXcm, WithOriginFilter},
@@ -55,6 +63,7 @@ parameter_types! {
X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into()));
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
} }
/// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`. /// Adapter for resolving `NetworkId` based on `pub storage Flavor: RuntimeFlavor`.
@@ -253,7 +262,12 @@ impl xcm_executor::Config for XcmConfig {
type SubscriptionService = PolkadotXcm; type SubscriptionService = PolkadotXcm;
type PalletInstancesInfo = AllPalletsWithSystem; type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = (); type FeeManager = XcmFeesToAccount<
Self,
RelayOrOtherSystemParachains<SystemParachains, Runtime>,
AccountId,
TreasuryAccount,
>;
type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter; type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter;
type UniversalAliases = Nothing; type UniversalAliases = Nothing;
type CallDispatcher = WithOriginFilter<SafeCallFilter>; type CallDispatcher = WithOriginFilter<SafeCallFilter>;
@@ -261,6 +275,9 @@ impl xcm_executor::Config for XcmConfig {
type Aliasers = Nothing; type Aliasers = Nothing;
} }
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// Converts a local signed origin into an XCM multilocation. /// Converts a local signed origin into an XCM multilocation.
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
@@ -269,7 +286,7 @@ pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, R
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -186,7 +186,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
XcmConfig::AssetTransactor::deposit_asset( XcmConfig::AssetTransactor::deposit_asset(
&ed, &ed,
&sibling_parachain_location, &sibling_parachain_location,
&XcmContext::with_message_id([0; 32]), Some(&XcmContext::with_message_id([0; 32])),
) )
.expect("deposited ed"); .expect("deposited ed");
} }
@@ -194,7 +194,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
XcmConfig::AssetTransactor::deposit_asset( XcmConfig::AssetTransactor::deposit_asset(
&fee, &fee,
&sibling_parachain_location, &sibling_parachain_location,
&XcmContext::with_message_id([0; 32]), Some(&XcmContext::with_message_id([0; 32])),
) )
.expect("deposited fee"); .expect("deposited fee");
@@ -45,6 +45,7 @@ pub mod fellowship;
pub use ambassador::pallet_ambassador_origins; pub use ambassador::pallet_ambassador_origins;
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use fellowship::{ use fellowship::{
migration::import_kusama_fellowship, pallet_fellowship_origins, Fellows, migration::import_kusama_fellowship, pallet_fellowship_origins, Fellows,
FellowshipCollectiveInstance, FellowshipCollectiveInstance,
@@ -98,7 +99,7 @@ pub use sp_runtime::BuildStorage;
// Polkadot imports // Polkadot imports
use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::BodyId; use xcm::latest::prelude::*;
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
@@ -401,6 +402,20 @@ impl parachain_info::Config for Runtime {}
impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(xcm_config::DotLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
TransactionByteFee,
XcmpQueue,
>;
impl cumulus_pallet_xcmp_queue::Config for Runtime { impl cumulus_pallet_xcmp_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
@@ -410,7 +425,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EitherOfDiverse<EnsureRoot<AccountId>, Fellows>; type ControllerOrigin = EitherOfDiverse<EnsureRoot<AccountId>, Fellows>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery =
polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -14,8 +14,9 @@
// limitations under the License. // limitations under the License.
use super::{ use super::{
AccountId, AllPalletsWithSystem, Balances, Fellows, ParachainInfo, ParachainSystem, AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, Fellows, ParachainInfo,
PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TransactionByteFee, WeightToFee, XcmpQueue,
}; };
use frame_support::{ use frame_support::{
match_types, parameter_types, match_types, parameter_types,
@@ -26,6 +27,7 @@ use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem}; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteAssetFromSystem};
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -279,11 +281,14 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -54,13 +54,14 @@ pallet-contracts = { path = "../../../../../substrate/frame/contracts", default-
pallet-contracts-primitives = { path = "../../../../../substrate/frame/contracts/primitives", default-features = false} pallet-contracts-primitives = { path = "../../../../../substrate/frame/contracts/primitives", default-features = false}
# Polkadot # Polkadot
pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false} pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm", default-features = false }
polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false} polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false }
polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false} polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", default-features = false }
polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false} polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false }
xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} rococo-runtime-constants = { path = "../../../../../polkadot/runtime/rococo/constants", default-features = false }
xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false }
# Cumulus # Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
@@ -115,6 +116,7 @@ std = [
"polkadot-core-primitives/std", "polkadot-core-primitives/std",
"polkadot-parachain-primitives/std", "polkadot-parachain-primitives/std",
"polkadot-runtime-common/std", "polkadot-runtime-common/std",
"rococo-runtime-constants/std",
"scale-info/std", "scale-info/std",
"sp-api/std", "sp-api/std",
"sp-block-builder/std", "sp-block-builder/std",
@@ -224,13 +224,17 @@ impl pallet_balances::Config for Runtime {
type MaxFreezes = ConstU32<0>; type MaxFreezes = ConstU32<0>;
} }
parameter_types! {
pub const TransactionByteFee: Balance = MILLICENTS;
}
impl pallet_transaction_payment::Config for Runtime { impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = type OnChargeTransaction =
pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees<Runtime>>; pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees<Runtime>>;
type WeightToFee = WeightToFee; type WeightToFee = WeightToFee;
/// Relay Chain `TransactionByteFee` / 10 /// Relay Chain `TransactionByteFee` / 10
type LengthToFee = ConstantMultiplier<Balance, ConstU128<MILLICENTS>>; type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
type OperationalFeeMultiplier = ConstU8<5>; type OperationalFeeMultiplier = ConstU8<5>;
} }
@@ -15,8 +15,9 @@
use super::{ use super::{
AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm,
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue,
}; };
use crate::common::rococo::currency::CENTS;
use frame_support::{ use frame_support::{
match_types, parameter_types, match_types, parameter_types,
traits::{ConstU32, EitherOfDiverse, Everything, Nothing}, traits::{ConstU32, EitherOfDiverse, Everything, Nothing},
@@ -24,8 +25,14 @@ use frame_support::{
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough};
use parachains_common::xcm_config::ConcreteAssetFromSystem; use parachains_common::{
xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains},
TREASURY_PALLET_ID,
};
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use rococo_runtime_constants::system_parachain::SystemParachains;
use sp_runtime::traits::AccountIdConversion;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -34,7 +41,7 @@ use xcm_builder::{
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WithComputedOrigin, WithUniqueTopic, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount,
}; };
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
@@ -44,7 +51,7 @@ parameter_types! {
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
pub const ExecutiveBody: BodyId = BodyId::Executive; pub const ExecutiveBody: BodyId = BodyId::Executive;
pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
} }
/// We allow root and the Relay Chain council to execute privileged collator selection operations. /// We allow root and the Relay Chain council to execute privileged collator selection operations.
@@ -167,7 +174,12 @@ impl xcm_executor::Config for XcmConfig {
type MaxAssetsIntoHolding = ConstU32<8>; type MaxAssetsIntoHolding = ConstU32<8>;
type AssetLocker = (); type AssetLocker = ();
type AssetExchanger = (); type AssetExchanger = ();
type FeeManager = (); type FeeManager = XcmFeesToAccount<
Self,
RelayOrOtherSystemParachains<SystemParachains, Runtime>,
AccountId,
TreasuryAccount,
>;
type MessageExporter = (); type MessageExporter = ();
type UniversalAliases = Nothing; type UniversalAliases = Nothing;
type CallDispatcher = RuntimeCall; type CallDispatcher = RuntimeCall;
@@ -179,11 +191,14 @@ impl xcm_executor::Config for XcmConfig {
/// Forms the basis for local origins sending/executing XCMs. /// Forms the basis for local origins sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
/// The means for routing XCM messages which are not for local execution into the right message /// The means for routing XCM messages which are not for local execution into the right message
/// queues. /// queues.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain: // Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>, cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains. // ..and XCMP to communicate with the sibling chains.
XcmpQueue, XcmpQueue,
)>; )>;
@@ -231,6 +246,20 @@ impl cumulus_pallet_xcm::Config for Runtime {
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
} }
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(RelayLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice<
FeeAssetId,
BaseDeliveryFee,
TransactionByteFee,
XcmpQueue,
>;
impl cumulus_pallet_xcmp_queue::Config for Runtime { impl cumulus_pallet_xcmp_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
@@ -243,7 +272,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
>; >;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight<Runtime>; type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -33,6 +33,7 @@ mod weights;
pub mod xcm_config; pub mod xcm_config;
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use frame_support::{ use frame_support::{
construct_runtime, construct_runtime,
dispatch::DispatchClass, dispatch::DispatchClass,
@@ -50,6 +51,7 @@ use frame_system::{
limits::{BlockLength, BlockWeights}, limits::{BlockLength, BlockWeights},
EnsureRoot, EnsureSigned, EnsureRoot, EnsureSigned,
}; };
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use smallvec::smallvec; use smallvec::smallvec;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
@@ -488,7 +490,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = (); type WeightInfo = ();
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -42,6 +42,7 @@ polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain", de
xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false}
xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false}
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false}
polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", default-features = false }
# Cumulus # Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
@@ -86,6 +87,7 @@ std = [
"parachain-info/std", "parachain-info/std",
"parachains-common/std", "parachains-common/std",
"polkadot-parachain-primitives/std", "polkadot-parachain-primitives/std",
"polkadot-runtime-common/std",
"scale-info/std", "scale-info/std",
"sp-api/std", "sp-api/std",
"sp-block-builder/std", "sp-block-builder/std",
@@ -118,6 +120,7 @@ runtime-benchmarks = [
"pallet-xcm/runtime-benchmarks", "pallet-xcm/runtime-benchmarks",
"parachains-common/runtime-benchmarks", "parachains-common/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-common/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks", "xcm-executor/runtime-benchmarks",
@@ -23,6 +23,8 @@
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::OpaqueMetadata; use sp_core::OpaqueMetadata;
use sp_runtime::{ use sp_runtime::{
@@ -511,7 +513,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>; type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight<Runtime>; type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight<Runtime>;
type PriceForSiblingDelivery = (); type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
} }
impl cumulus_pallet_dmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime {
+1 -1
View File
@@ -96,7 +96,7 @@ pub struct ChannelInfo {
pub trait GetChannelInfo { pub trait GetChannelInfo {
fn get_channel_status(id: ParaId) -> ChannelStatus; fn get_channel_status(id: ParaId) -> ChannelStatus;
fn get_channel_max(id: ParaId) -> Option<usize>; fn get_channel_info(id: ParaId) -> Option<ChannelInfo>;
} }
/// Something that should be called when sending an upward message. /// Something that should be called when sending an upward message.
+8 -3
View File
@@ -15,11 +15,12 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features
sp-std = { path = "../../../substrate/primitives/std", default-features = false} sp-std = { path = "../../../substrate/primitives/std", default-features = false}
# Polkadot # Polkadot
polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false} polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-features = false }
xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false} polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false }
xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false} xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false}
xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false} xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false}
pallet-xcm-benchmarks = { path = "../../../polkadot/xcm/pallet-xcm-benchmarks", default-features = false }
# Cumulus # Cumulus
cumulus-primitives-core = { path = "../core", default-features = false } cumulus-primitives-core = { path = "../core", default-features = false }
@@ -30,7 +31,9 @@ std = [
"codec/std", "codec/std",
"cumulus-primitives-core/std", "cumulus-primitives-core/std",
"frame-support/std", "frame-support/std",
"pallet-xcm-benchmarks/std",
"polkadot-runtime-common/std", "polkadot-runtime-common/std",
"polkadot-runtime-parachains/std",
"sp-io/std", "sp-io/std",
"sp-runtime/std", "sp-runtime/std",
"sp-std/std", "sp-std/std",
@@ -41,7 +44,9 @@ std = [
runtime-benchmarks = [ runtime-benchmarks = [
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
"pallet-xcm-benchmarks/runtime-benchmarks",
"polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks", "xcm-executor/runtime-benchmarks",
+60 -23
View File
@@ -28,29 +28,13 @@ use frame_support::{
}, },
weights::Weight, weights::Weight,
}; };
use polkadot_runtime_common::xcm_sender::ConstantPrice; use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery;
use sp_runtime::{traits::Saturating, SaturatedConversion}; use sp_runtime::{traits::Saturating, SaturatedConversion};
use sp_std::{marker::PhantomData, prelude::*}; use sp_std::{marker::PhantomData, prelude::*};
use xcm::{latest::prelude::*, WrapVersion}; use xcm::{latest::prelude::*, WrapVersion};
use xcm_builder::TakeRevenue; use xcm_builder::TakeRevenue;
use xcm_executor::traits::{MatchesFungibles, TransactAsset, WeightTrader}; use xcm_executor::traits::{MatchesFungibles, TransactAsset, WeightTrader};
pub trait PriceForParentDelivery {
fn price_for_parent_delivery(message: &Xcm<()>) -> MultiAssets;
}
impl PriceForParentDelivery for () {
fn price_for_parent_delivery(_: &Xcm<()>) -> MultiAssets {
MultiAssets::new()
}
}
impl<T: Get<MultiAssets>> PriceForParentDelivery for ConstantPrice<T> {
fn price_for_parent_delivery(_: &Xcm<()>) -> MultiAssets {
T::get()
}
}
/// Xcm router which recognises the `Parent` destination and handles it by sending the message into /// Xcm router which recognises the `Parent` destination and handles it by sending the message into
/// the given UMP `UpwardMessageSender` implementation. Thus this essentially adapts an /// the given UMP `UpwardMessageSender` implementation. Thus this essentially adapts an
/// `UpwardMessageSender` trait impl into a `SendXcm` trait impl. /// `UpwardMessageSender` trait impl into a `SendXcm` trait impl.
@@ -63,7 +47,7 @@ impl<T, W, P> SendXcm for ParentAsUmp<T, W, P>
where where
T: UpwardMessageSender, T: UpwardMessageSender,
W: WrapVersion, W: WrapVersion,
P: PriceForParentDelivery, P: PriceForMessageDelivery<Id = ()>,
{ {
type Ticket = Vec<u8>; type Ticket = Vec<u8>;
@@ -76,7 +60,7 @@ where
if d.contains_parents_only(1) { if d.contains_parents_only(1) {
// An upward message for the relay chain. // An upward message for the relay chain.
let xcm = msg.take().ok_or(SendError::MissingArgument)?; let xcm = msg.take().ok_or(SendError::MissingArgument)?;
let price = P::price_for_parent_delivery(&xcm); let price = P::price_for_delivery((), &xcm);
let versioned_xcm = let versioned_xcm =
W::wrap_version(&d, xcm).map_err(|()| SendError::DestinationUnsupported)?; W::wrap_version(&d, xcm).map_err(|()| SendError::DestinationUnsupported)?;
let data = versioned_xcm.encode(); let data = versioned_xcm.encode();
@@ -280,7 +264,7 @@ pub struct XcmFeesTo32ByteAccount<FungiblesMutateAdapter, AccountId, ReceiverAcc
impl< impl<
FungiblesMutateAdapter: TransactAsset, FungiblesMutateAdapter: TransactAsset,
AccountId: Clone + Into<[u8; 32]>, AccountId: Clone + Into<[u8; 32]>,
ReceiverAccount: frame_support::traits::Get<Option<AccountId>>, ReceiverAccount: Get<Option<AccountId>>,
> TakeRevenue for XcmFeesTo32ByteAccount<FungiblesMutateAdapter, AccountId, ReceiverAccount> > TakeRevenue for XcmFeesTo32ByteAccount<FungiblesMutateAdapter, AccountId, ReceiverAccount>
{ {
fn take_revenue(revenue: MultiAsset) { fn take_revenue(revenue: MultiAsset) {
@@ -288,9 +272,7 @@ impl<
let ok = FungiblesMutateAdapter::deposit_asset( let ok = FungiblesMutateAdapter::deposit_asset(
&revenue, &revenue,
&(X1(AccountId32 { network: None, id: receiver.into() }).into()), &(X1(AccountId32 { network: None, id: receiver.into() }).into()),
// We aren't able to track the XCM that initiated the fee deposit, so we create a None,
// fake message hash here
&XcmContext::with_message_id([0; 32]),
) )
.is_ok(); .is_ok();
@@ -542,3 +524,58 @@ mod tests {
assert_eq!(trader.buy_weight(weight_to_buy, payment, &ctx), Err(XcmError::NotWithdrawable)); assert_eq!(trader.buy_weight(weight_to_buy, payment, &ctx), Err(XcmError::NotWithdrawable));
} }
} }
/// Implementation of `pallet_xcm_benchmarks::EnsureDelivery` which helps to ensure delivery to the
/// parent relay chain. Deposits existential deposit for origin (if needed).
/// Deposits estimated fee to the origin account (if needed).
/// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded).
#[cfg(feature = "runtime-benchmarks")]
pub struct ToParentDeliveryHelper<XcmConfig, ExistentialDeposit, PriceForDelivery>(
sp_std::marker::PhantomData<(XcmConfig, ExistentialDeposit, PriceForDelivery)>,
);
#[cfg(feature = "runtime-benchmarks")]
impl<
XcmConfig: xcm_executor::Config,
ExistentialDeposit: Get<Option<MultiAsset>>,
PriceForDelivery: PriceForMessageDelivery<Id = ()>,
> pallet_xcm_benchmarks::EnsureDelivery
for ToParentDeliveryHelper<XcmConfig, ExistentialDeposit, PriceForDelivery>
{
fn ensure_successful_delivery(
origin_ref: &MultiLocation,
_dest: &MultiLocation,
fee_reason: xcm_executor::traits::FeeReason,
) -> (Option<xcm_executor::FeesMode>, Option<MultiAssets>) {
use xcm::latest::{MAX_INSTRUCTIONS_TO_DECODE, MAX_ITEMS_IN_MULTIASSETS};
use xcm_executor::{traits::FeeManager, FeesMode};
let mut fees_mode = None;
if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) {
// if not waived, we need to set up accounts for paying and receiving fees
// mint ED to origin if needed
if let Some(ed) = ExistentialDeposit::get() {
XcmConfig::AssetTransactor::deposit_asset(&ed, &origin_ref, None).unwrap();
}
// overestimate delivery fee
let mut max_assets: Vec<MultiAsset> = Vec::new();
for i in 0..MAX_ITEMS_IN_MULTIASSETS {
max_assets.push((GeneralIndex(i as u128), 100u128).into());
}
let overestimated_xcm =
vec![WithdrawAsset(max_assets.into()); MAX_INSTRUCTIONS_TO_DECODE as usize].into();
let overestimated_fees = PriceForDelivery::price_for_delivery((), &overestimated_xcm);
// mint overestimated fee to origin
for fee in overestimated_fees.inner() {
XcmConfig::AssetTransactor::deposit_asset(&fee, &origin_ref, None).unwrap();
}
// expected worst case - direct withdraw
fees_mode = Some(FeesMode { jit_withdraw: true });
}
(fees_mode, None)
}
}
+3 -3
View File
@@ -1335,10 +1335,10 @@ pub struct TestContext<T, Origin: Chain, Destination: Chain> {
pub args: T, pub args: T,
} }
/// Struct that help with tests where either dispatchables or assertions need /// Struct that helps with tests where either dispatchables or assertions need
/// to be reused. The struct keeps the test's arguments of your choice in the generic `Args`. /// to be reused. The struct keeps the test's arguments of your choice in the generic `Args`.
/// These arguments can be easily reused and shared between the assertions functions /// These arguments can be easily reused and shared between the assertion functions
/// and dispatchables functions, which are also stored in `Test`. /// and dispatchable functions, which are also stored in `Test`.
/// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution. /// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution.
/// `Destination` corresponds to the last chain where an effect of the intial execution is expected /// `Destination` corresponds to the last chain where an effect of the intial execution is expected
/// happen. `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke /// happen. `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke
+1 -1
View File
@@ -333,7 +333,7 @@ impl DmpMessageHandler for () {
} }
/// The aggregate XCMP message format. /// The aggregate XCMP message format.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
pub enum XcmpMessageFormat { pub enum XcmpMessageFormat {
/// Encoded `VersionedXcm` messages, all concatenated. /// Encoded `VersionedXcm` messages, all concatenated.
ConcatenatedVersionedXcm, ConcatenatedVersionedXcm,
+7
View File
@@ -52,6 +52,9 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac
slot-range-helper = { path = "slot_range_helper", default-features = false } slot-range-helper = { path = "slot_range_helper", default-features = false }
xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } xcm = { package = "staging-xcm", path = "../../xcm", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false, optional = true }
pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true }
xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false }
[dev-dependencies] [dev-dependencies]
@@ -89,6 +92,7 @@ std = [
"pallet-transaction-payment/std", "pallet-transaction-payment/std",
"pallet-treasury/std", "pallet-treasury/std",
"pallet-vesting/std", "pallet-vesting/std",
"pallet-xcm-benchmarks/std",
"parity-scale-codec/std", "parity-scale-codec/std",
"primitives/std", "primitives/std",
"runtime-parachains/std", "runtime-parachains/std",
@@ -105,6 +109,7 @@ std = [
"sp-staking/std", "sp-staking/std",
"sp-std/std", "sp-std/std",
"xcm-builder/std", "xcm-builder/std",
"xcm-executor/std",
"xcm/std", "xcm/std",
] ]
runtime-benchmarks = [ runtime-benchmarks = [
@@ -123,11 +128,13 @@ runtime-benchmarks = [
"pallet-timestamp/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks",
"pallet-treasury/runtime-benchmarks", "pallet-treasury/runtime-benchmarks",
"pallet-vesting/runtime-benchmarks", "pallet-vesting/runtime-benchmarks",
"pallet-xcm-benchmarks/runtime-benchmarks",
"primitives/runtime-benchmarks", "primitives/runtime-benchmarks",
"runtime-parachains/runtime-benchmarks", "runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks",
"sp-staking/runtime-benchmarks", "sp-staking/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
] ]
try-runtime = [ try-runtime = [
"frame-election-provider-support/try-runtime", "frame-election-provider-support/try-runtime",
+147 -22
View File
@@ -31,38 +31,63 @@ use SendError::*;
/// Simple value-bearing trait for determining/expressing the assets required to be paid for a /// Simple value-bearing trait for determining/expressing the assets required to be paid for a
/// messages to be delivered to a parachain. /// messages to be delivered to a parachain.
pub trait PriceForParachainDelivery { pub trait PriceForMessageDelivery {
/// Type used for charging different prices to different destinations
type Id;
/// Return the assets required to deliver `message` to the given `para` destination. /// Return the assets required to deliver `message` to the given `para` destination.
fn price_for_parachain_delivery(para: ParaId, message: &Xcm<()>) -> MultiAssets; fn price_for_delivery(id: Self::Id, message: &Xcm<()>) -> MultiAssets;
} }
impl PriceForParachainDelivery for () { impl PriceForMessageDelivery for () {
fn price_for_parachain_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets { type Id = ();
fn price_for_delivery(_: Self::Id, _: &Xcm<()>) -> MultiAssets {
MultiAssets::new() MultiAssets::new()
} }
} }
/// Implementation of `PriceForParachainDelivery` which returns a fixed price. pub struct NoPriceForMessageDelivery<Id>(PhantomData<Id>);
impl<Id> PriceForMessageDelivery for NoPriceForMessageDelivery<Id> {
type Id = Id;
fn price_for_delivery(_: Self::Id, _: &Xcm<()>) -> MultiAssets {
MultiAssets::new()
}
}
/// Implementation of [`PriceForMessageDelivery`] which returns a fixed price.
pub struct ConstantPrice<T>(sp_std::marker::PhantomData<T>); pub struct ConstantPrice<T>(sp_std::marker::PhantomData<T>);
impl<T: Get<MultiAssets>> PriceForParachainDelivery for ConstantPrice<T> { impl<T: Get<MultiAssets>> PriceForMessageDelivery for ConstantPrice<T> {
fn price_for_parachain_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets { type Id = ();
fn price_for_delivery(_: Self::Id, _: &Xcm<()>) -> MultiAssets {
T::get() T::get()
} }
} }
/// Implementation of `PriceForParachainDelivery` which returns an exponentially increasing price. /// Implementation of [`PriceForMessageDelivery`] which returns an exponentially increasing price.
/// The `A` type parameter is used to denote the asset ID that will be used for paying the delivery
/// fee.
///
/// The formula for the fee is based on the sum of a base fee plus a message length fee, multiplied /// The formula for the fee is based on the sum of a base fee plus a message length fee, multiplied
/// by a specified factor. In mathematical form, it is `F * (B + encoded_msg_len * M)`. /// by a specified factor. In mathematical form:
///
/// `F * (B + encoded_msg_len * M)`
///
/// Thus, if F = 1 and M = 0, this type is equivalent to [`ConstantPrice<B>`].
///
/// The type parameters are understood as follows:
///
/// - `A`: Used to denote the asset ID that will be used for paying the delivery fee.
/// - `B`: The base fee to pay for message delivery.
/// - `M`: The fee to pay for each and every byte of the message after encoding it.
/// - `F`: A fee factor multiplier. It can be understood as the exponent term in the formula.
pub struct ExponentialPrice<A, B, M, F>(sp_std::marker::PhantomData<(A, B, M, F)>); pub struct ExponentialPrice<A, B, M, F>(sp_std::marker::PhantomData<(A, B, M, F)>);
impl<A: Get<AssetId>, B: Get<u128>, M: Get<u128>, F: FeeTracker> PriceForParachainDelivery impl<A: Get<AssetId>, B: Get<u128>, M: Get<u128>, F: FeeTracker> PriceForMessageDelivery
for ExponentialPrice<A, B, M, F> for ExponentialPrice<A, B, M, F>
{ {
fn price_for_parachain_delivery(para: ParaId, msg: &Xcm<()>) -> MultiAssets { type Id = F::Id;
fn price_for_delivery(id: Self::Id, msg: &Xcm<()>) -> MultiAssets {
let msg_fee = (msg.encoded_size() as u128).saturating_mul(M::get()); let msg_fee = (msg.encoded_size() as u128).saturating_mul(M::get());
let fee_sum = B::get().saturating_add(msg_fee); let fee_sum = B::get().saturating_add(msg_fee);
let amount = F::get_fee_factor(para).saturating_mul_int(fee_sum); let amount = F::get_fee_factor(id).saturating_mul_int(fee_sum);
(A::get(), amount).into() (A::get(), amount).into()
} }
} }
@@ -70,8 +95,10 @@ impl<A: Get<AssetId>, B: Get<u128>, M: Get<u128>, F: FeeTracker> PriceForParacha
/// XCM sender for relay chain. It only sends downward message. /// XCM sender for relay chain. It only sends downward message.
pub struct ChildParachainRouter<T, W, P>(PhantomData<(T, W, P)>); pub struct ChildParachainRouter<T, W, P>(PhantomData<(T, W, P)>);
impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion, P: PriceForParachainDelivery> impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion, P> SendXcm
SendXcm for ChildParachainRouter<T, W, P> for ChildParachainRouter<T, W, P>
where
P: PriceForMessageDelivery<Id = ParaId>,
{ {
type Ticket = (HostConfiguration<BlockNumberFor<T>>, ParaId, Vec<u8>); type Ticket = (HostConfiguration<BlockNumberFor<T>>, ParaId, Vec<u8>);
@@ -91,7 +118,7 @@ impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion, P: PriceForPar
let xcm = msg.take().ok_or(MissingArgument)?; let xcm = msg.take().ok_or(MissingArgument)?;
let config = <configuration::Pallet<T>>::config(); let config = <configuration::Pallet<T>>::config();
let para = id.into(); let para = id.into();
let price = P::price_for_parachain_delivery(para, &xcm); let price = P::price_for_delivery(para, &xcm);
let blob = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?.encode(); let blob = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?.encode();
<dmp::Pallet<T>>::can_queue_downward_message(&config, &para, &blob) <dmp::Pallet<T>>::can_queue_downward_message(&config, &para, &blob)
.map_err(Into::<SendError>::into)?; .map_err(Into::<SendError>::into)?;
@@ -109,6 +136,94 @@ impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion, P: PriceForPar
} }
} }
/// Implementation of `pallet_xcm_benchmarks::EnsureDelivery` which helps to ensure delivery to the
/// `ParaId` parachain (sibling or child). Deposits existential deposit for origin (if needed).
/// Deposits estimated fee to the origin account (if needed).
/// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded).
#[cfg(feature = "runtime-benchmarks")]
pub struct ToParachainDeliveryHelper<
XcmConfig,
ExistentialDeposit,
PriceForDelivery,
ParaId,
ToParaIdHelper,
>(
sp_std::marker::PhantomData<(
XcmConfig,
ExistentialDeposit,
PriceForDelivery,
ParaId,
ToParaIdHelper,
)>,
);
#[cfg(feature = "runtime-benchmarks")]
impl<
XcmConfig: xcm_executor::Config,
ExistentialDeposit: Get<Option<MultiAsset>>,
PriceForDelivery: PriceForMessageDelivery<Id = ParaId>,
Parachain: Get<ParaId>,
ToParachainHelper: EnsureForParachain,
> pallet_xcm_benchmarks::EnsureDelivery
for ToParachainDeliveryHelper<
XcmConfig,
ExistentialDeposit,
PriceForDelivery,
Parachain,
ToParachainHelper,
>
{
fn ensure_successful_delivery(
origin_ref: &MultiLocation,
_dest: &MultiLocation,
fee_reason: xcm_executor::traits::FeeReason,
) -> (Option<xcm_executor::FeesMode>, Option<MultiAssets>) {
use xcm_executor::{
traits::{FeeManager, TransactAsset},
FeesMode,
};
let mut fees_mode = None;
if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) {
// if not waived, we need to set up accounts for paying and receiving fees
// mint ED to origin if needed
if let Some(ed) = ExistentialDeposit::get() {
XcmConfig::AssetTransactor::deposit_asset(&ed, &origin_ref, None).unwrap();
}
// overestimate delivery fee
let overestimated_xcm = vec![ClearOrigin; 128].into();
let overestimated_fees =
PriceForDelivery::price_for_delivery(Parachain::get(), &overestimated_xcm);
// mint overestimated fee to origin
for fee in overestimated_fees.inner() {
XcmConfig::AssetTransactor::deposit_asset(&fee, &origin_ref, None).unwrap();
}
// allow more initialization for target parachain
ToParachainHelper::ensure(Parachain::get());
// expected worst case - direct withdraw
fees_mode = Some(FeesMode { jit_withdraw: true });
}
(fees_mode, None)
}
}
/// Ensure more initialization for `ParaId`. (e.g. open HRMP channels, ...)
#[cfg(feature = "runtime-benchmarks")]
pub trait EnsureForParachain {
fn ensure(para_id: ParaId);
}
#[cfg(feature = "runtime-benchmarks")]
impl EnsureForParachain for () {
fn ensure(_: ParaId) {
// doing nothing
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -124,7 +239,17 @@ mod tests {
struct TestFeeTracker; struct TestFeeTracker;
impl FeeTracker for TestFeeTracker { impl FeeTracker for TestFeeTracker {
fn get_fee_factor(_: ParaId) -> FixedU128 { type Id = ParaId;
fn get_fee_factor(_: Self::Id) -> FixedU128 {
FixedU128::from_rational(101, 100)
}
fn increase_fee_factor(_: Self::Id, _: FixedU128) -> FixedU128 {
FixedU128::from_rational(101, 100)
}
fn decrease_fee_factor(_: Self::Id) -> FixedU128 {
FixedU128::from_rational(101, 100) FixedU128::from_rational(101, 100)
} }
} }
@@ -142,21 +267,21 @@ mod tests {
// message_length = 1 // message_length = 1
let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + m); let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + m);
assert_eq!( assert_eq!(
TestExponentialPrice::price_for_parachain_delivery(id, &Xcm(vec![])), TestExponentialPrice::price_for_delivery(id, &Xcm(vec![])),
(FeeAssetId::get(), result).into() (FeeAssetId::get(), result).into()
); );
// message size = 2 // message size = 2
let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (2 * m)); let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (2 * m));
assert_eq!( assert_eq!(
TestExponentialPrice::price_for_parachain_delivery(id, &Xcm(vec![ClearOrigin])), TestExponentialPrice::price_for_delivery(id, &Xcm(vec![ClearOrigin])),
(FeeAssetId::get(), result).into() (FeeAssetId::get(), result).into()
); );
// message size = 4 // message size = 4
let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (4 * m)); let result: u128 = TestFeeTracker::get_fee_factor(id).saturating_mul_int(b + (4 * m));
assert_eq!( assert_eq!(
TestExponentialPrice::price_for_parachain_delivery( TestExponentialPrice::price_for_delivery(
id, id,
&Xcm(vec![SetAppendix(Xcm(vec![ClearOrigin]))]) &Xcm(vec![SetAppendix(Xcm(vec![ClearOrigin]))])
), ),
+20 -27
View File
@@ -17,12 +17,12 @@
//! To prevent Out of Memory errors on the `DownwardMessageQueue`, an //! To prevent Out of Memory errors on the `DownwardMessageQueue`, an
//! exponential fee factor (`DeliveryFeeFactor`) is set. The fee factor //! exponential fee factor (`DeliveryFeeFactor`) is set. The fee factor
//! increments exponentially after the number of messages in the //! increments exponentially after the number of messages in the
//! `DownwardMessageQueue` pass a threshold. This threshold is set as: //! `DownwardMessageQueue` passes a threshold. This threshold is set as:
//! //!
//! ```ignore //! ```ignore
//! // Maximum max sized messages that can be send to //! // Maximum max sized messages that can be send to
//! // the DownwardMessageQueue before it runs out of memory //! // the DownwardMessageQueue before it runs out of memory
//! max_messsages = MAX_POSSIBLE_ALLOCATION / max_downward_message_size //! max_messages = MAX_POSSIBLE_ALLOCATION / max_downward_message_size
//! threshold = max_messages / THRESHOLD_FACTOR //! threshold = max_messages / THRESHOLD_FACTOR
//! ``` //! ```
//! Based on the THRESHOLD_FACTOR, the threshold is set as a fraction of the //! Based on the THRESHOLD_FACTOR, the threshold is set as a fraction of the
@@ -144,7 +144,7 @@ pub mod pallet {
FixedU128::from_u32(1) FixedU128::from_u32(1)
} }
/// The number to multiply the base delivery fee by. /// The factor to multiply the base delivery fee by.
#[pallet::storage] #[pallet::storage]
pub(crate) type DeliveryFeeFactor<T: Config> = pub(crate) type DeliveryFeeFactor<T: Config> =
StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>; StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>;
@@ -243,10 +243,9 @@ impl<T: Config> Pallet<T> {
let threshold = let threshold =
Self::dmq_max_length(config.max_downward_message_size).saturating_div(THRESHOLD_FACTOR); Self::dmq_max_length(config.max_downward_message_size).saturating_div(THRESHOLD_FACTOR);
if q_len > (threshold as usize) { if q_len > (threshold as usize) {
let message_size_factor = let message_size_factor = FixedU128::from((serialized_len / 1024) as u128)
FixedU128::from_u32(serialized_len.saturating_div(1024) as u32) .saturating_mul(MESSAGE_SIZE_FEE_BASE);
.saturating_mul(MESSAGE_SIZE_FEE_BASE); Self::increase_fee_factor(para, message_size_factor);
Self::increment_fee_factor(para, message_size_factor);
} }
Ok(()) Ok(())
@@ -304,7 +303,7 @@ impl<T: Config> Pallet<T> {
let threshold = let threshold =
Self::dmq_max_length(config.max_downward_message_size).saturating_div(THRESHOLD_FACTOR); Self::dmq_max_length(config.max_downward_message_size).saturating_div(THRESHOLD_FACTOR);
if q_len <= (threshold as usize) { if q_len <= (threshold as usize) {
Self::decrement_fee_factor(para); Self::decrease_fee_factor(para);
} }
T::DbWeight::get().reads_writes(1, 1) T::DbWeight::get().reads_writes(1, 1)
} }
@@ -337,32 +336,26 @@ impl<T: Config> Pallet<T> {
) -> Vec<InboundDownwardMessage<BlockNumberFor<T>>> { ) -> Vec<InboundDownwardMessage<BlockNumberFor<T>>> {
DownwardMessageQueues::<T>::get(&recipient) DownwardMessageQueues::<T>::get(&recipient)
} }
}
/// Raise the delivery fee factor by a multiplicative factor and stores the resulting value. impl<T: Config> FeeTracker for Pallet<T> {
/// type Id = ParaId;
/// Returns the new delivery fee factor after the increment.
pub(crate) fn increment_fee_factor(para: ParaId, message_size_factor: FixedU128) -> FixedU128 { fn get_fee_factor(id: Self::Id) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(para, |f| { DeliveryFeeFactor::<T>::get(id)
*f = f.saturating_mul(EXPONENTIAL_FEE_BASE + message_size_factor); }
fn increase_fee_factor(id: Self::Id, message_size_factor: FixedU128) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(id, |f| {
*f = f.saturating_mul(EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor));
*f *f
}) })
} }
/// Reduce the delivery fee factor by a multiplicative factor and stores the resulting value. fn decrease_fee_factor(id: Self::Id) -> FixedU128 {
/// <DeliveryFeeFactor<T>>::mutate(id, |f| {
/// Does not reduce the fee factor below the initial value, which is currently set as 1.
///
/// Returns the new delivery fee factor after the decrement.
pub(crate) fn decrement_fee_factor(para: ParaId) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(para, |f| {
*f = InitialFactor::get().max(*f / EXPONENTIAL_FEE_BASE); *f = InitialFactor::get().max(*f / EXPONENTIAL_FEE_BASE);
*f *f
}) })
} }
} }
impl<T: Config> FeeTracker for Pallet<T> {
fn get_fee_factor(para: ParaId) -> FixedU128 {
DeliveryFeeFactor::<T>::get(para)
}
}
+1 -1
View File
@@ -233,7 +233,7 @@ fn verify_dmq_mqc_head_is_externally_accessible() {
} }
#[test] #[test]
fn verify_fee_increment_and_decrement() { fn verify_fee_increase_and_decrease() {
let a = ParaId::from(123); let a = ParaId::from(123);
let mut genesis = default_genesis_config(); let mut genesis = default_genesis_config();
genesis.configuration.config.max_downward_message_size = 16777216; genesis.configuration.config.max_downward_message_size = 16777216;
+15 -1
View File
@@ -59,7 +59,21 @@ use sp_runtime::{DispatchResult, FixedU128};
/// Trait for tracking message delivery fees on a transport protocol. /// Trait for tracking message delivery fees on a transport protocol.
pub trait FeeTracker { pub trait FeeTracker {
fn get_fee_factor(para: ParaId) -> FixedU128; /// Type used for assigning different fee factors to different destinations
type Id;
/// Returns the evolving exponential fee factor which will be used to calculate the delivery
/// fees.
fn get_fee_factor(id: Self::Id) -> FixedU128;
/// Increases the delivery fee factor by a factor based on message size and records the result.
///
/// Returns the new delivery fee factor after the increase.
fn increase_fee_factor(id: Self::Id, message_size_factor: FixedU128) -> FixedU128;
/// Decreases the delivery fee factor by a constant factor and records the result.
///
/// Does not reduce the fee factor below the initial value, which is currently set as 1.
///
/// Returns the new delivery fee factor after the decrease.
fn decrease_fee_factor(id: Self::Id) -> FixedU128;
} }
/// Schedule a para to be initialized at the start of the next session with the given genesis data. /// Schedule a para to be initialized at the start of the next session with the given genesis data.
@@ -16,6 +16,8 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime", default-featur
sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false }
sp-core = { path = "../../../../substrate/primitives/core", default-features = false } sp-core = { path = "../../../../substrate/primitives/core", default-features = false }
xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false }
[features] [features]
default = [ "std" ] default = [ "std" ]
std = [ std = [
@@ -25,4 +27,5 @@ std = [
"sp-core/std", "sp-core/std",
"sp-runtime/std", "sp-runtime/std",
"sp-weights/std", "sp-weights/std",
"xcm/std",
] ]
@@ -100,6 +100,26 @@ pub mod fee {
} }
} }
/// System Parachains.
pub mod system_parachain {
use xcm::latest::prelude::*;
/// Network's Asset Hub parachain ID.
pub const ASSET_HUB_ID: u32 = 1000;
/// Contracts parachain ID.
pub const CONTRACTS_ID: u32 = 1002;
/// Encointer parachain ID.
pub const ENCOINTER_ID: u32 = 1003;
/// BridgeHub parachain ID.
pub const BRIDGE_HUB_ID: u32 = 1013;
frame_support::match_types! {
pub type SystemParachains: impl Contains<MultiLocation> = {
MultiLocation { parents: 0, interior: X1(Parachain(ASSET_HUB_ID | CONTRACTS_ID | ENCOINTER_ID | BRIDGE_HUB_ID)) }
};
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{ use super::{
+17 -1
View File
@@ -2072,14 +2072,29 @@ sp_api::impl_runtime_apis! {
use sp_storage::TrackedStorageKey; use sp_storage::TrackedStorageKey;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::{ use xcm_config::{
LocalCheckAccount, LocationConverter, AssetHub, TokenLocation, XcmConfig, AssetHub, LocalCheckAccount, LocationConverter, TokenLocation, XcmConfig,
}; };
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
TokenLocation::get(),
ExistentialDeposit::get()
).into());
pub ToParachain: ParaId = rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into();
}
impl frame_system_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {}
impl frame_benchmarking::baseline::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = XcmConfig; type XcmConfig = XcmConfig;
type AccountIdConverter = LocationConverter; type AccountIdConverter = LocationConverter;
type DeliveryHelper = runtime_common::xcm_sender::ToParachainDeliveryHelper<
XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForChildParachainDelivery,
ToParachain,
(),
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(AssetHub::get()) Ok(AssetHub::get())
} }
@@ -2116,6 +2131,7 @@ sp_api::impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
+18 -15
View File
@@ -18,7 +18,7 @@
use super::{ use super::{
parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, Fellows, ParaId, Runtime, parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, Fellows, ParaId, Runtime,
RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmPallet, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, Treasury, WeightToFee, XcmPallet,
}; };
use crate::governance::StakingAdmin; use crate::governance::StakingAdmin;
@@ -29,7 +29,7 @@ use frame_support::{
weights::Weight, weights::Weight,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
use rococo_runtime_constants::currency::CENTS; use rococo_runtime_constants::{currency::CENTS, system_parachain::*};
use runtime_common::{ use runtime_common::{
xcm_sender::{ChildParachainRouter, ExponentialPrice}, xcm_sender::{ChildParachainRouter, ExponentialPrice},
ToAuthor, ToAuthor,
@@ -43,7 +43,7 @@ use xcm_builder::{
DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete, DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete,
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount,
}; };
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
@@ -53,6 +53,7 @@ parameter_types! {
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
pub CheckAccount: AccountId = XcmPallet::check_account(); pub CheckAccount: AccountId = XcmPallet::check_account();
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
pub TreasuryAccount: Option<AccountId> = Some(Treasury::account_id());
} }
pub type LocationConverter = ( pub type LocationConverter = (
@@ -100,22 +101,22 @@ parameter_types! {
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3); pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
} }
pub type PriceForChildParachainDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>;
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our /// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
/// individual routers. /// individual routers.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<
// Only one router so far - use DMP to communicate with child parachains. // Only one router so far - use DMP to communicate with child parachains.
ChildParachainRouter< ChildParachainRouter<Runtime, XcmPallet, PriceForChildParachainDelivery>,
Runtime, >;
XcmPallet,
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
>,
)>;
parameter_types! { parameter_types! {
pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }); pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const AssetHub: MultiLocation = Parachain(1000).into_location(); pub const AssetHub: MultiLocation = Parachain(ASSET_HUB_ID).into_location();
pub const Contracts: MultiLocation = Parachain(1002).into_location(); pub const Contracts: MultiLocation = Parachain(CONTRACTS_ID).into_location();
pub const Encointer: MultiLocation = Parachain(1003).into_location(); pub const Encointer: MultiLocation = Parachain(ENCOINTER_ID).into_location();
pub const BridgeHub: MultiLocation = Parachain(BRIDGE_HUB_ID).into_location();
pub const Tick: MultiLocation = Parachain(100).into_location(); pub const Tick: MultiLocation = Parachain(100).into_location();
pub const Trick: MultiLocation = Parachain(110).into_location(); pub const Trick: MultiLocation = Parachain(110).into_location();
pub const Track: MultiLocation = Parachain(120).into_location(); pub const Track: MultiLocation = Parachain(120).into_location();
@@ -125,6 +126,7 @@ parameter_types! {
pub const RocForAssetHub: (MultiAssetFilter, MultiLocation) = (Roc::get(), AssetHub::get()); pub const RocForAssetHub: (MultiAssetFilter, MultiLocation) = (Roc::get(), AssetHub::get());
pub const RocForContracts: (MultiAssetFilter, MultiLocation) = (Roc::get(), Contracts::get()); pub const RocForContracts: (MultiAssetFilter, MultiLocation) = (Roc::get(), Contracts::get());
pub const RocForEncointer: (MultiAssetFilter, MultiLocation) = (Roc::get(), Encointer::get()); pub const RocForEncointer: (MultiAssetFilter, MultiLocation) = (Roc::get(), Encointer::get());
pub const RocForBridgeHub: (MultiAssetFilter, MultiLocation) = (Roc::get(), BridgeHub::get());
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
} }
@@ -135,6 +137,7 @@ pub type TrustedTeleporters = (
xcm_builder::Case<RocForAssetHub>, xcm_builder::Case<RocForAssetHub>,
xcm_builder::Case<RocForContracts>, xcm_builder::Case<RocForContracts>,
xcm_builder::Case<RocForEncointer>, xcm_builder::Case<RocForEncointer>,
xcm_builder::Case<RocForBridgeHub>,
); );
match_types! { match_types! {
@@ -188,7 +191,7 @@ impl xcm_executor::Config for XcmConfig {
type SubscriptionService = XcmPallet; type SubscriptionService = XcmPallet;
type PalletInstancesInfo = AllPalletsWithSystem; type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = (); type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
type MessageExporter = (); type MessageExporter = ();
type UniversalAliases = Nothing; type UniversalAliases = Nothing;
type CallDispatcher = RuntimeCall; type CallDispatcher = RuntimeCall;
@@ -206,7 +209,7 @@ parameter_types! {
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
parameter_types! { parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into()); pub ReachableDest: Option<MultiLocation> = Some(Parachain(ASSET_HUB_ID).into());
} }
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior
@@ -60,7 +60,11 @@ pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
pub struct DummyAssetTransactor; pub struct DummyAssetTransactor;
impl TransactAsset for DummyAssetTransactor { impl TransactAsset for DummyAssetTransactor {
fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation, _context: &XcmContext) -> XcmResult { fn deposit_asset(
_what: &MultiAsset,
_who: &MultiLocation,
_context: Option<&XcmContext>,
) -> XcmResult {
Ok(()) Ok(())
} }
@@ -16,6 +16,8 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime", default-featur
sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false }
sp-core = { path = "../../../../substrate/primitives/core", default-features = false } sp-core = { path = "../../../../substrate/primitives/core", default-features = false }
xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false }
[features] [features]
default = [ "std" ] default = [ "std" ]
std = [ std = [
@@ -25,4 +27,5 @@ std = [
"sp-core/std", "sp-core/std",
"sp-runtime/std", "sp-runtime/std",
"sp-weights/std", "sp-weights/std",
"xcm/std",
] ]
+18 -8
View File
@@ -96,6 +96,24 @@ pub mod fee {
} }
} }
/// System Parachains.
pub mod system_parachain {
use xcm::latest::prelude::*;
/// Network's Asset Hub parachain ID.
pub const ASSET_HUB_ID: u32 = 1000;
/// Collectives parachain ID.
pub const COLLECTIVES_ID: u32 = 1001;
/// BridgeHub parachain ID.
pub const BRIDGE_HUB_ID: u32 = 1002;
frame_support::match_types! {
pub type SystemParachains: impl Contains<MultiLocation> = {
MultiLocation { parents: 0, interior: X1(Parachain(ASSET_HUB_ID | COLLECTIVES_ID | BRIDGE_HUB_ID ))}
};
}
}
/// XCM protocol related constants. /// XCM protocol related constants.
pub mod xcm { pub mod xcm {
/// Pluralistic bodies existing within the consensus. /// Pluralistic bodies existing within the consensus.
@@ -108,14 +126,6 @@ pub mod xcm {
} }
} }
/// System Parachains.
pub mod system_parachain {
/// Statemint parachain ID.
pub const ASSET_HUB_ID: u32 = 1000;
/// Collectives parachain ID.
pub const COLLECTIVES_ID: u32 = 1001;
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{ use super::{
+16
View File
@@ -2182,9 +2182,24 @@ sp_api::impl_runtime_apis! {
}; };
use xcm_config::{AssetHub, TokenLocation}; use xcm_config::{AssetHub, TokenLocation};
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
TokenLocation::get(),
ExistentialDeposit::get()
).into());
pub ToParachain: ParaId = westend_runtime_constants::system_parachain::ASSET_HUB_ID.into();
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig; type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationConverter; type AccountIdConverter = xcm_config::LocationConverter;
type DeliveryHelper = runtime_common::xcm_sender::ToParachainDeliveryHelper<
xcm_config::XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForChildParachainDelivery,
ToParachain,
(),
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(AssetHub::get()) Ok(AssetHub::get())
} }
@@ -2221,6 +2236,7 @@ sp_api::impl_runtime_apis! {
} }
impl pallet_xcm_benchmarks::generic::Config for Runtime { impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -17,7 +17,7 @@
//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
//! //!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2023-10-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000` //! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 //! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
@@ -55,8 +55,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `101` // Measured: `101`
// Estimated: `3593` // Estimated: `3593`
// Minimum execution time: 24_642_000 picoseconds. // Minimum execution time: 24_815_000 picoseconds.
Weight::from_parts(24_973_000, 3593) Weight::from_parts(25_098_000, 3593)
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@@ -66,8 +66,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `101` // Measured: `101`
// Estimated: `6196` // Estimated: `6196`
// Minimum execution time: 50_882_000 picoseconds. // Minimum execution time: 51_268_000 picoseconds.
Weight::from_parts(51_516_000, 6196) Weight::from_parts(51_857_000, 6196)
.saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes(2))
} }
@@ -85,8 +85,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `210` // Measured: `210`
// Estimated: `6196` // Estimated: `6196`
// Minimum execution time: 73_923_000 picoseconds. // Minimum execution time: 74_113_000 picoseconds.
Weight::from_parts(75_454_000, 6196) Weight::from_parts(74_721_000, 6196)
.saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
} }
@@ -111,8 +111,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `109` // Measured: `109`
// Estimated: `3574` // Estimated: `3574`
// Minimum execution time: 29_035_000 picoseconds. // Minimum execution time: 28_919_000 picoseconds.
Weight::from_parts(30_086_000, 3574) Weight::from_parts(29_703_000, 3574)
.saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes(2))
} }
@@ -122,8 +122,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `103` // Measured: `103`
// Estimated: `3593` // Estimated: `3593`
// Minimum execution time: 22_094_000 picoseconds. // Minimum execution time: 21_685_000 picoseconds.
Weight::from_parts(22_560_000, 3593) Weight::from_parts(22_528_000, 3593)
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@@ -133,8 +133,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `0` // Measured: `0`
// Estimated: `3593` // Estimated: `3593`
// Minimum execution time: 24_771_000 picoseconds. // Minimum execution time: 25_192_000 picoseconds.
Weight::from_parts(25_280_000, 3593) Weight::from_parts(25_445_000, 3593)
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@@ -152,8 +152,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `109` // Measured: `109`
// Estimated: `3593` // Estimated: `3593`
// Minimum execution time: 49_777_000 picoseconds. // Minimum execution time: 49_349_000 picoseconds.
Weight::from_parts(50_833_000, 3593) Weight::from_parts(50_476_000, 3593)
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes(3))
} }
@@ -171,8 +171,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `109` // Measured: `109`
// Estimated: `3593` // Estimated: `3593`
// Minimum execution time: 51_425_000 picoseconds. // Minimum execution time: 51_386_000 picoseconds.
Weight::from_parts(52_213_000, 3593) Weight::from_parts(52_141_000, 3593)
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes(3))
} }
+24 -18
View File
@@ -19,7 +19,7 @@
use super::{ use super::{
parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin, parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin,
GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin,
TransactionByteFee, WeightToFee, XcmPallet, TransactionByteFee, Treasury, WeightToFee, XcmPallet,
}; };
use frame_support::{ use frame_support::{
@@ -44,6 +44,7 @@ use xcm_builder::{
DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeesToAccount,
}; };
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
@@ -53,6 +54,7 @@ parameter_types! {
pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get())); pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
pub CheckAccount: AccountId = XcmPallet::check_account(); pub CheckAccount: AccountId = XcmPallet::check_account();
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
pub TreasuryAccount: Option<AccountId> = Some(Treasury::account_id());
/// The asset ID for the asset that we use to pay for message delivery fees. /// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(TokenLocation::get()); pub FeeAssetId: AssetId = Concrete(TokenLocation::get());
/// The base fee for the message delivery fees. /// The base fee for the message delivery fees.
@@ -95,29 +97,38 @@ type LocalOriginConverter = (
XcmPassthrough<RuntimeOrigin>, XcmPassthrough<RuntimeOrigin>,
); );
pub type PriceForChildParachainDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>;
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our /// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
/// individual routers. /// individual routers.
pub type XcmRouter = WithUniqueTopic<( pub type XcmRouter = WithUniqueTopic<
// Only one router so far - use DMP to communicate with child parachains. // Only one router so far - use DMP to communicate with child parachains.
ChildParachainRouter< ChildParachainRouter<Runtime, XcmPallet, PriceForChildParachainDelivery>,
Runtime, >;
XcmPallet,
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
>,
)>;
parameter_types! { parameter_types! {
pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const AssetHub: MultiLocation = Parachain(ASSET_HUB_ID).into_location(); pub const AssetHub: MultiLocation = Parachain(ASSET_HUB_ID).into_location();
pub const WndForAssetHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), AssetHub::get());
pub const Collectives: MultiLocation = Parachain(COLLECTIVES_ID).into_location(); pub const Collectives: MultiLocation = Parachain(COLLECTIVES_ID).into_location();
pub const BridgeHub: MultiLocation = Parachain(BRIDGE_HUB_ID).into_location();
pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const WndForAssetHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), AssetHub::get());
pub const WndForCollectives: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Collectives::get()); pub const WndForCollectives: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Collectives::get());
pub const WndForBridgeHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), BridgeHub::get());
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
} }
pub type TrustedTeleporters = #[cfg(feature = "runtime-benchmarks")]
(xcm_builder::Case<WndForAssetHub>, xcm_builder::Case<WndForCollectives>); parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(ASSET_HUB_ID).into());
}
pub type TrustedTeleporters = (
xcm_builder::Case<WndForAssetHub>,
xcm_builder::Case<WndForCollectives>,
xcm_builder::Case<WndForBridgeHub>,
);
match_types! { match_types! {
pub type OnlyParachains: impl Contains<MultiLocation> = { pub type OnlyParachains: impl Contains<MultiLocation> = {
@@ -174,7 +185,7 @@ impl xcm_executor::Config for XcmConfig {
type SubscriptionService = XcmPallet; type SubscriptionService = XcmPallet;
type PalletInstancesInfo = AllPalletsWithSystem; type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = (); type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
type MessageExporter = (); type MessageExporter = ();
type UniversalAliases = Nothing; type UniversalAliases = Nothing;
type CallDispatcher = RuntimeCall; type CallDispatcher = RuntimeCall;
@@ -191,11 +202,6 @@ parameter_types! {
pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX);
} }
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
}
/// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. /// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value.
pub type GeneralAdminToPlurality = pub type GeneralAdminToPlurality =
OriginToPluralityVoice<RuntimeOrigin, GeneralAdmin, GeneralAdminBodyId>; OriginToPluralityVoice<RuntimeOrigin, GeneralAdmin, GeneralAdminBodyId>;
@@ -15,7 +15,7 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*; use super::*;
use crate::{account_and_location, new_executor, AssetTransactorOf, XcmCallOf}; use crate::{account_and_location, new_executor, AssetTransactorOf, EnsureDelivery, XcmCallOf};
use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError, BenchmarkResult}; use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError, BenchmarkResult};
use frame_support::{ use frame_support::{
pallet_prelude::Get, pallet_prelude::Get,
@@ -24,8 +24,8 @@ use frame_support::{
}; };
use sp_runtime::traits::{Bounded, Zero}; use sp_runtime::traits::{Bounded, Zero};
use sp_std::{prelude::*, vec}; use sp_std::{prelude::*, vec};
use xcm::latest::prelude::*; use xcm::latest::{prelude::*, MAX_ITEMS_IN_MULTIASSETS};
use xcm_executor::traits::{ConvertLocation, TransactAsset}; use xcm_executor::traits::{ConvertLocation, FeeReason, TransactAsset};
benchmarks_instance_pallet! { benchmarks_instance_pallet! {
where_clause { where where_clause { where
@@ -45,15 +45,7 @@ benchmarks_instance_pallet! {
let worst_case_holding = T::worst_case_holding(0); let worst_case_holding = T::worst_case_holding(0);
let asset = T::get_multi_asset(); let asset = T::get_multi_asset();
<AssetTransactorOf<T>>::deposit_asset( <AssetTransactorOf<T>>::deposit_asset(&asset, &sender_location, None).unwrap();
&asset,
&sender_location,
&XcmContext {
origin: Some(sender_location.clone()),
message_id: [0; 32],
topic: None,
},
).unwrap();
// check the assets of origin. // check the assets of origin.
assert!(!T::TransactAsset::balance(&sender_account).is_zero()); assert!(!T::TransactAsset::balance(&sender_account).is_zero());
@@ -78,15 +70,7 @@ benchmarks_instance_pallet! {
let dest_location = T::valid_destination()?; let dest_location = T::valid_destination()?;
let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap();
<AssetTransactorOf<T>>::deposit_asset( <AssetTransactorOf<T>>::deposit_asset(&asset, &sender_location, None).unwrap();
&asset,
&sender_location,
&XcmContext {
origin: Some(sender_location.clone()),
message_id: [0; 32],
topic: None,
},
).unwrap();
assert!(T::TransactAsset::balance(&dest_account).is_zero()); assert!(T::TransactAsset::balance(&dest_account).is_zero());
let mut executor = new_executor::<T>(sender_location); let mut executor = new_executor::<T>(sender_location);
@@ -104,20 +88,27 @@ benchmarks_instance_pallet! {
let dest_location = T::valid_destination()?; let dest_location = T::valid_destination()?;
let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap();
let asset = T::get_multi_asset(); let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
<AssetTransactorOf<T>>::deposit_asset(
&asset,
&sender_location, &sender_location,
&XcmContext { &dest_location,
origin: Some(sender_location.clone()), FeeReason::TransferReserveAsset
message_id: [0; 32], );
topic: None, let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
},
).unwrap(); let asset = T::get_multi_asset();
<AssetTransactorOf<T>>::deposit_asset(&asset, &sender_location, None).unwrap();
assert!(T::TransactAsset::balance(&sender_account) > sender_account_balance_before);
let assets: MultiAssets = vec![ asset ].into(); let assets: MultiAssets = vec![ asset ].into();
assert!(T::TransactAsset::balance(&dest_account).is_zero()); assert!(T::TransactAsset::balance(&dest_account).is_zero());
let mut executor = new_executor::<T>(sender_location); let mut executor = new_executor::<T>(sender_location);
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let instruction = Instruction::TransferReserveAsset { let instruction = Instruction::TransferReserveAsset {
assets, assets,
dest: dest_location, dest: dest_location,
@@ -127,7 +118,7 @@ benchmarks_instance_pallet! {
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
assert!(T::TransactAsset::balance(&sender_account).is_zero()); assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
assert!(!T::TransactAsset::balance(&dest_account).is_zero()); assert!(!T::TransactAsset::balance(&dest_account).is_zero());
// TODO: Check sender queue is not empty. #4426 // TODO: Check sender queue is not empty. #4426
} }
@@ -150,16 +141,33 @@ benchmarks_instance_pallet! {
} }
initiate_reserve_withdraw { initiate_reserve_withdraw {
let (sender_account, sender_location) = account_and_location::<T>(1);
let holding = T::worst_case_holding(1); let holding = T::worst_case_holding(1);
let assets_filter = MultiAssetFilter::Definite(holding.clone()); let assets_filter = MultiAssetFilter::Definite(holding.clone().into_inner().into_iter().take(MAX_ITEMS_IN_MULTIASSETS).collect::<Vec<_>>().into());
let reserve = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let reserve = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
let mut executor = new_executor::<T>(Default::default());
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&sender_location,
&reserve,
FeeReason::InitiateReserveWithdraw,
);
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(sender_location);
executor.set_holding(holding.into()); executor.set_holding(holding.into());
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let instruction = Instruction::InitiateReserveWithdraw { assets: assets_filter, reserve, xcm: Xcm(vec![]) }; let instruction = Instruction::InitiateReserveWithdraw { assets: assets_filter, reserve, xcm: Xcm(vec![]) };
let xcm = Xcm(vec![instruction]); let xcm = Xcm(vec![instruction]);
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
// The execute completing successfully is as good as we can check. // The execute completing successfully is as good as we can check.
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
} }
@@ -19,7 +19,7 @@
use crate::{fungible as xcm_balances_benchmark, mock::*}; use crate::{fungible as xcm_balances_benchmark, mock::*};
use frame_benchmarking::BenchmarkError; use frame_benchmarking::BenchmarkError;
use frame_support::{ use frame_support::{
parameter_types, derive_impl, parameter_types,
traits::{ConstU32, Everything, Nothing}, traits::{ConstU32, Everything, Nothing},
weights::Weight, weights::Weight,
}; };
@@ -75,20 +75,10 @@ parameter_types! {
pub const ExistentialDeposit: u64 = 7; pub const ExistentialDeposit: u64 = 7;
} }
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)]
impl pallet_balances::Config for Test { impl pallet_balances::Config for Test {
type MaxLocks = ();
type MaxReserves = ();
type ReserveIdentifier = [u8; 8]; type ReserveIdentifier = [u8; 8];
type Balance = u64;
type DustRemoval = ();
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System; type AccountStore = System;
type WeightInfo = ();
type RuntimeHoldReason = RuntimeHoldReason;
type FreezeIdentifier = ();
type MaxHolds = ConstU32<0>;
type MaxFreezes = ConstU32<0>;
} }
parameter_types! { parameter_types! {
@@ -157,6 +147,7 @@ impl xcm_executor::Config for XcmConfig {
impl crate::Config for Test { impl crate::Config for Test {
type XcmConfig = XcmConfig; type XcmConfig = XcmConfig;
type AccountIdConverter = AccountIdConverter; type AccountIdConverter = AccountIdConverter;
type DeliveryHelper = ();
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
let valid_destination: MultiLocation = let valid_destination: MultiLocation =
X1(AccountId32 { network: None, id: [0u8; 32] }).into(); X1(AccountId32 { network: None, id: [0u8; 32] }).into();
@@ -15,27 +15,45 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*; use super::*;
use crate::{new_executor, XcmCallOf}; use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf};
use codec::Encode; use codec::Encode;
use frame_benchmarking::{benchmarks, BenchmarkError}; use frame_benchmarking::{benchmarks, BenchmarkError};
use frame_support::dispatch::GetDispatchInfo; use frame_support::{dispatch::GetDispatchInfo, traits::fungible::Inspect};
use sp_std::vec; use sp_std::vec;
use xcm::{ use xcm::{
latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight}, latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight},
DoubleEncoded, DoubleEncoded,
}; };
use xcm_executor::{ExecutorError, FeesMode}; use xcm_executor::{
traits::{ConvertLocation, FeeReason},
ExecutorError, FeesMode,
};
benchmarks! { benchmarks! {
report_holding { report_holding {
let (sender_account, sender_location) = account_and_location::<T>(1);
let holding = T::worst_case_holding(0); let holding = T::worst_case_holding(0);
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
let mut executor = new_executor::<T>(Default::default()); let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&sender_location,
&destination,
FeeReason::Report,
);
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(sender_location);
executor.set_holding(holding.clone().into()); executor.set_holding(holding.clone().into());
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let instruction = Instruction::<XcmCallOf<T>>::ReportHolding { let instruction = Instruction::<XcmCallOf<T>>::ReportHolding {
response_info: QueryResponseInfo { response_info: QueryResponseInfo {
destination: T::valid_destination()?, destination,
query_id: Default::default(), query_id: Default::default(),
max_weight: Weight::MAX, max_weight: Weight::MAX,
}, },
@@ -44,11 +62,11 @@ benchmarks! {
}; };
let xcm = Xcm(vec![instruction]); let xcm = Xcm(vec![instruction]);
} : { } : {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// The completion of execution above is enough to validate this is completed. // Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
} }
// This benchmark does not use any additional orders or instructions. This should be managed // This benchmark does not use any additional orders or instructions. This should be managed
@@ -182,11 +200,26 @@ benchmarks! {
} }
report_error { report_error {
let mut executor = new_executor::<T>(Default::default()); let (sender_account, sender_location) = account_and_location::<T>(1);
executor.set_error(Some((0u32, XcmError::Unimplemented)));
let query_id = Default::default(); let query_id = Default::default();
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
let max_weight = Default::default(); let max_weight = Default::default();
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&sender_location,
&destination,
FeeReason::Report,
);
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(sender_location);
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
executor.set_error(Some((0u32, XcmError::Unimplemented)));
let instruction = Instruction::ReportError(QueryResponseInfo { let instruction = Instruction::ReportError(QueryResponseInfo {
query_id, destination, max_weight query_id, destination, max_weight
@@ -195,7 +228,8 @@ benchmarks! {
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// the execution succeeding is all we need to verify this xcm was successful // Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
} }
claim_asset { claim_asset {
@@ -360,10 +394,24 @@ benchmarks! {
} }
query_pallet { query_pallet {
let (sender_account, sender_location) = account_and_location::<T>(1);
let query_id = Default::default(); let query_id = Default::default();
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
let max_weight = Default::default(); let max_weight = Default::default();
let mut executor = new_executor::<T>(Default::default());
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&sender_location,
&destination,
FeeReason::QueryPallet,
);
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(sender_location);
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let instruction = Instruction::QueryPallet { let instruction = Instruction::QueryPallet {
module_name: b"frame_system".to_vec(), module_name: b"frame_system".to_vec(),
@@ -373,6 +421,8 @@ benchmarks! {
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
} }
@@ -394,11 +444,25 @@ benchmarks! {
} }
report_transact_status { report_transact_status {
let (sender_account, sender_location) = account_and_location::<T>(1);
let query_id = Default::default(); let query_id = Default::default();
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
let max_weight = Default::default(); let max_weight = Default::default();
let mut executor = new_executor::<T>(Default::default()); let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&sender_location,
&destination,
FeeReason::Report,
);
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(sender_location);
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
executor.set_transact_status(b"MyError".to_vec().into()); executor.set_transact_status(b"MyError".to_vec().into());
let instruction = Instruction::ReportTransactStatus(QueryResponseInfo { let instruction = Instruction::ReportTransactStatus(QueryResponseInfo {
@@ -410,6 +474,8 @@ benchmarks! {
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
} }
@@ -491,14 +557,30 @@ benchmarks! {
let inner_xcm = Xcm(vec![ClearOrigin; x as usize]); let inner_xcm = Xcm(vec![ClearOrigin; x as usize]);
// Get `origin`, `network` and `destination` from configured runtime. // Get `origin`, `network` and `destination` from configured runtime.
let (origin, network, destination) = T::export_message_origin_and_destination()?; let (origin, network, destination) = T::export_message_origin_and_destination()?;
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&origin,
&destination.into(),
FeeReason::Export(network),
);
let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap();
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(origin); let mut executor = new_executor::<T>(origin);
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let xcm = Xcm(vec![ExportMessage { let xcm = Xcm(vec![ExportMessage {
network, destination, xcm: inner_xcm, network, destination, xcm: inner_xcm,
}]); }]);
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// The execute completing successfully is as good as we can check. // Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
} }
@@ -517,14 +599,30 @@ benchmarks! {
lock_asset { lock_asset {
let (unlocker, owner, asset) = T::unlockable_asset()?; let (unlocker, owner, asset) = T::unlockable_asset()?;
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&owner,
&unlocker,
FeeReason::LockAsset,
);
let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap();
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
let mut executor = new_executor::<T>(owner); let mut executor = new_executor::<T>(owner);
executor.set_holding(asset.clone().into()); executor.set_holding(asset.clone().into());
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let instruction = Instruction::LockAsset { asset, unlocker }; let instruction = Instruction::LockAsset { asset, unlocker };
let xcm = Xcm(vec![instruction]); let xcm = Xcm(vec![instruction]);
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// Check delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
} }
@@ -595,13 +693,29 @@ benchmarks! {
.enact() .enact()
.map_err(|_| BenchmarkError::Skip)?; .map_err(|_| BenchmarkError::Skip)?;
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
&owner,
&locker,
FeeReason::RequestUnlock,
);
let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap();
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
// ... then request for an unlock with the RequestUnlock instruction. // ... then request for an unlock with the RequestUnlock instruction.
let mut executor = new_executor::<T>(owner); let mut executor = new_executor::<T>(owner);
if let Some(expected_fees_mode) = expected_fees_mode {
executor.set_fees_mode(expected_fees_mode);
}
if let Some(expected_assets_in_holding) = expected_assets_in_holding {
executor.set_holding(expected_assets_in_holding.into());
}
let instruction = Instruction::RequestUnlock { asset, locker }; let instruction = Instruction::RequestUnlock { asset, locker };
let xcm = Xcm(vec![instruction]); let xcm = Xcm(vec![instruction]);
}: { }: {
executor.bench_process(xcm)?; executor.bench_process(xcm)?;
} verify { } verify {
// Check we charged the delivery fees
assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
// TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426
} }
@@ -19,7 +19,7 @@
use crate::{generic, mock::*, *}; use crate::{generic, mock::*, *};
use codec::Decode; use codec::Decode;
use frame_support::{ use frame_support::{
match_types, parameter_types, derive_impl, match_types, parameter_types,
traits::{Everything, OriginTrait}, traits::{Everything, OriginTrait},
weights::Weight, weights::Weight,
}; };
@@ -40,6 +40,7 @@ frame_support::construct_runtime!(
pub enum Test pub enum Test
{ {
System: frame_system::{Pallet, Call, Config<T>, Storage, Event<T>}, System: frame_system::{Pallet, Call, Config<T>, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
XcmGenericBenchmarks: generic::{Pallet}, XcmGenericBenchmarks: generic::{Pallet},
} }
); );
@@ -79,7 +80,11 @@ impl frame_system::Config for Test {
/// The benchmarks in this pallet should never need an asset transactor to begin with. /// The benchmarks in this pallet should never need an asset transactor to begin with.
pub struct NoAssetTransactor; pub struct NoAssetTransactor;
impl xcm_executor::traits::TransactAsset for NoAssetTransactor { impl xcm_executor::traits::TransactAsset for NoAssetTransactor {
fn deposit_asset(_: &MultiAsset, _: &MultiLocation, _: &XcmContext) -> Result<(), XcmError> { fn deposit_asset(
_: &MultiAsset,
_: &MultiLocation,
_: Option<&XcmContext>,
) -> Result<(), XcmError> {
unreachable!(); unreachable!();
} }
@@ -133,9 +138,20 @@ impl xcm_executor::Config for XcmConfig {
type Aliasers = Aliasers; type Aliasers = Aliasers;
} }
parameter_types! {
pub const ExistentialDeposit: u64 = 7;
}
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)]
impl pallet_balances::Config for Test {
type ReserveIdentifier = [u8; 8];
type AccountStore = System;
}
impl crate::Config for Test { impl crate::Config for Test {
type XcmConfig = XcmConfig; type XcmConfig = XcmConfig;
type AccountIdConverter = AccountIdConverter; type AccountIdConverter = AccountIdConverter;
type DeliveryHelper = ();
fn valid_destination() -> Result<MultiLocation, BenchmarkError> { fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
let valid_destination: MultiLocation = let valid_destination: MultiLocation =
Junction::AccountId32 { network: None, id: [0u8; 32] }.into(); Junction::AccountId32 { network: None, id: [0u8; 32] }.into();
@@ -151,6 +167,7 @@ impl crate::Config for Test {
} }
impl generic::Config for Test { impl generic::Config for Test {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) { fn worst_case_response() -> (u64, Response) {
@@ -183,7 +200,7 @@ impl generic::Config for Test {
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> { fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> {
let assets: MultiAsset = (Concrete(Here.into()), 100).into(); let assets: MultiAsset = (Concrete(Here.into()), 100).into();
Ok((Default::default(), Default::default(), assets)) Ok((Default::default(), account_id_junction::<Test>(1).into(), assets))
} }
fn export_message_origin_and_destination( fn export_message_origin_and_destination(
@@ -38,6 +38,11 @@ pub mod pallet {
+ From<frame_system::Call<Self>> + From<frame_system::Call<Self>>
+ Encode; + Encode;
/// The type of `fungible` that is being used under the hood.
///
/// This is useful for testing and checking.
type TransactAsset: frame_support::traits::fungible::Mutate<Self::AccountId>;
/// The response which causes the most runtime weight. /// The response which causes the most runtime weight.
fn worst_case_response() -> (u64, Response); fn worst_case_response() -> (u64, Response);
+33 -1
View File
@@ -22,7 +22,10 @@ use codec::Encode;
use frame_benchmarking::{account, BenchmarkError}; use frame_benchmarking::{account, BenchmarkError};
use sp_std::prelude::*; use sp_std::prelude::*;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_executor::{traits::ConvertLocation, Config as XcmConfig}; use xcm_executor::{
traits::{ConvertLocation, FeeReason},
Config as XcmConfig, FeesMode,
};
pub mod fungible; pub mod fungible;
pub mod generic; pub mod generic;
@@ -41,6 +44,9 @@ pub trait Config: frame_system::Config {
/// A converter between a multi-location to a sovereign account. /// A converter between a multi-location to a sovereign account.
type AccountIdConverter: ConvertLocation<Self::AccountId>; type AccountIdConverter: ConvertLocation<Self::AccountId>;
/// Helper that ensures successful delivery for XCM instructions which need `SendXcm`.
type DeliveryHelper: EnsureDelivery;
/// Does any necessary setup to create a valid destination for XCM messages. /// Does any necessary setup to create a valid destination for XCM messages.
/// Returns that destination's multi-location to be used in benchmarks. /// Returns that destination's multi-location to be used in benchmarks.
fn valid_destination() -> Result<MultiLocation, BenchmarkError>; fn valid_destination() -> Result<MultiLocation, BenchmarkError>;
@@ -108,3 +114,29 @@ pub fn account_and_location<T: Config>(index: u32) -> (T::AccountId, MultiLocati
(account, location) (account, location)
} }
/// Trait for a type which ensures all requirements for successful delivery with XCM transport
/// layers.
pub trait EnsureDelivery {
/// Prepare all requirements for successful `XcmSender: SendXcm` passing (accounts, balances,
/// channels ...). Returns:
/// - possible `FeesMode` which is expected to be set to executor
/// - possible `MultiAssets` which are expected to be subsume to the Holding Register
fn ensure_successful_delivery(
origin_ref: &MultiLocation,
dest: &MultiLocation,
fee_reason: FeeReason,
) -> (Option<FeesMode>, Option<MultiAssets>);
}
/// `()` implementation does nothing which means no special requirements for environment.
impl EnsureDelivery for () {
fn ensure_successful_delivery(
_origin_ref: &MultiLocation,
_dest: &MultiLocation,
_fee_reason: FeeReason,
) -> (Option<FeesMode>, Option<MultiAssets>) {
// doing nothing
(None, None)
}
}
+55 -8
View File
@@ -16,8 +16,8 @@
use codec::Encode; use codec::Encode;
use frame_support::{ use frame_support::{
construct_runtime, parameter_types, construct_runtime, match_types, parameter_types,
traits::{ConstU32, Everything, Nothing}, traits::{ConstU32, Everything, EverythingBut, Nothing},
weights::Weight, weights::Weight,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -25,14 +25,16 @@ use polkadot_parachain_primitives::primitives::Id as ParaId;
use polkadot_runtime_parachains::origin; use polkadot_runtime_parachains::origin;
use sp_core::H256; use sp_core::H256;
use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage};
pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData}; pub use sp_std::{
cell::RefCell, collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData,
};
use xcm::prelude::*; use xcm::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible,
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount,
}; };
use xcm_executor::XcmExecutor; use xcm_executor::XcmExecutor;
@@ -154,7 +156,7 @@ pub(crate) fn take_sent_xcm() -> Vec<(MultiLocation, Xcm<()>)> {
r r
}) })
} }
/// Sender that never returns error, always sends /// Sender that never returns error.
pub struct TestSendXcm; pub struct TestSendXcm;
impl SendXcm for TestSendXcm { impl SendXcm for TestSendXcm {
type Ticket = (MultiLocation, Xcm<()>); type Ticket = (MultiLocation, Xcm<()>);
@@ -193,6 +195,38 @@ impl SendXcm for TestSendXcmErrX8 {
} }
} }
parameter_types! {
pub Para3000: u32 = 3000;
pub Para3000Location: MultiLocation = Parachain(Para3000::get()).into();
pub Para3000PaymentAmount: u128 = 1;
pub Para3000PaymentMultiAssets: MultiAssets = MultiAssets::from(MultiAsset::from((Here, Para3000PaymentAmount::get())));
}
/// Sender only sends to `Parachain(3000)` destination requiring payment.
pub struct TestPaidForPara3000SendXcm;
impl SendXcm for TestPaidForPara3000SendXcm {
type Ticket = (MultiLocation, Xcm<()>);
fn validate(
dest: &mut Option<MultiLocation>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<(MultiLocation, Xcm<()>)> {
if let Some(dest) = dest.as_ref() {
if !dest.eq(&Para3000Location::get()) {
return Err(SendError::NotApplicable)
}
} else {
return Err(SendError::NotApplicable)
}
let pair = (dest.take().unwrap(), msg.take().unwrap());
Ok((pair, Para3000PaymentMultiAssets::get()))
}
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
let hash = fake_message_hash(&pair.1);
SENT_XCM.with(|q| q.borrow_mut().push(pair));
Ok(hash)
}
}
parameter_types! { parameter_types! {
pub const BlockHashCount: u64 = 250; pub const BlockHashCount: u64 = 250;
} }
@@ -271,6 +305,14 @@ parameter_types! {
pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into());
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]);
}
pub const XCM_FEES_NOT_WAIVED_USER_ACCOUNT: [u8; 32] = [37u8; 32];
match_types! {
pub type XcmFeesNotWaivedLocations: impl Contains<MultiLocation> = {
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 {network: None, id: XCM_FEES_NOT_WAIVED_USER_ACCOUNT})}
};
} }
pub type Barrier = ( pub type Barrier = (
@@ -283,7 +325,7 @@ pub type Barrier = (
pub struct XcmConfig; pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig { impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
type XcmSender = TestSendXcm; type XcmSender = (TestPaidForPara3000SendXcm, TestSendXcm);
type AssetTransactor = LocalAssetTransactor; type AssetTransactor = LocalAssetTransactor;
type OriginConverter = LocalOriginConverter; type OriginConverter = LocalOriginConverter;
type IsReserve = (); type IsReserve = ();
@@ -300,7 +342,12 @@ impl xcm_executor::Config for XcmConfig {
type SubscriptionService = XcmPallet; type SubscriptionService = XcmPallet;
type PalletInstancesInfo = AllPalletsWithSystem; type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = (); type FeeManager = XcmFeesToAccount<
Self,
EverythingBut<XcmFeesNotWaivedLocations>,
AccountId,
XcmFeesTargetAccount,
>;
type MessageExporter = (); type MessageExporter = ();
type UniversalAliases = Nothing; type UniversalAliases = Nothing;
type CallDispatcher = RuntimeCall; type CallDispatcher = RuntimeCall;
@@ -322,7 +369,7 @@ parameter_types! {
impl pallet_xcm::Config for Test { impl pallet_xcm::Config for Test {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmRouter = (TestSendXcmErrX8, TestSendXcm); type XcmRouter = (TestSendXcmErrX8, TestPaidForPara3000SendXcm, TestSendXcm);
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmExecuteFilter = Everything; type XcmExecuteFilter = Everything;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
+68
View File
@@ -522,6 +522,74 @@ fn reserve_transfer_assets_works() {
}); });
} }
/// Test `reserve_transfer_assets_with_paid_router_works`
///
/// Asserts that the sender's balance is decreased and the beneficiary's balance
/// is increased. Verifies the correct message is sent and event is emitted.
/// Verifies that XCM router fees (`SendXcm::validate` -> `MultiAssets`) are withdrawn from correct
/// user account and deposited to a correct target account (`XcmFeesTargetAccount`).
#[test]
fn reserve_transfer_assets_with_paid_router_works() {
let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT);
let paid_para_id = Para3000::get();
let balances = vec![
(user_account.clone(), INITIAL_BALANCE),
(ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE),
(XcmFeesTargetAccount::get(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let xcm_router_fee_amount = Para3000PaymentAmount::get();
let weight = BaseXcmWeight::get() * 2;
let dest: MultiLocation =
Junction::AccountId32 { network: None, id: user_account.clone().into() }.into();
assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE);
assert_ok!(XcmPallet::reserve_transfer_assets(
RuntimeOrigin::signed(user_account.clone()),
Box::new(Parachain(paid_para_id).into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
));
// check event
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
// XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount
assert_eq!(
Balances::free_balance(user_account),
INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount
);
// Destination account (parachain account) has amount
let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating();
assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT);
// XcmFeesTargetAccount where should lend xcm_router_fee_amount
assert_eq!(
Balances::free_balance(XcmFeesTargetAccount::get()),
INITIAL_BALANCE + xcm_router_fee_amount
);
assert_eq!(
sent_xcm(),
vec![(
Parachain(paid_para_id).into(),
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Parent, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `limited_reserve_transfer_assets` /// Test `limited_reserve_transfer_assets`
/// ///
/// Asserts that the sender's balance is decreased and the beneficiary's balance /// Asserts that the sender's balance is decreased and the beneficiary's balance
+3 -3
View File
@@ -45,7 +45,7 @@ pub use junction::{BodyId, BodyPart, Junction, NetworkId};
pub use junctions::Junctions; pub use junctions::Junctions;
pub use multiasset::{ pub use multiasset::{
AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
WildFungibility, WildMultiAsset, WildFungibility, WildMultiAsset, MAX_ITEMS_IN_MULTIASSETS,
}; };
pub use multilocation::{ pub use multilocation::{
Ancestor, AncestorThen, InteriorMultiLocation, MultiLocation, Parent, ParentThen, Ancestor, AncestorThen, InteriorMultiLocation, MultiLocation, Parent, ParentThen,
@@ -70,7 +70,7 @@ pub type QueryId = u64;
#[scale_info(bounds(), skip_type_params(Call))] #[scale_info(bounds(), skip_type_params(Call))]
pub struct Xcm<Call>(pub Vec<Instruction<Call>>); pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;
environmental::environmental!(instructions_count: u8); environmental::environmental!(instructions_count: u8);
@@ -932,7 +932,7 @@ pub enum Instruction<Call> {
/// should be sent on arrival. /// should be sent on arrival.
/// - `xcm`: The message to be exported. /// - `xcm`: The message to be exported.
/// ///
/// As an example, to export a message for execution on Statemine (parachain #1000 in the /// As an example, to export a message for execution on Asset Hub (parachain #1000 in the
/// Kusama network), you would call with `network: NetworkId::Kusama` and /// Kusama network), you would call with `network: NetworkId::Kusama` and
/// `destination: X1(Parachain(1000))`. Alternatively, to export a message for execution on /// `destination: X1(Parachain(1000))`. Alternatively, to export a message for execution on
/// Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`. /// Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`.
@@ -191,7 +191,11 @@ impl<
} }
} }
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> Result { fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
_context: Option<&XcmContext>,
) -> Result {
log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who); log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who);
// Check we handle this asset. // Check we handle this asset.
let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotHandled)?; let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotHandled)?;
@@ -0,0 +1,58 @@
// Copyright Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
use core::marker::PhantomData;
use frame_support::traits::{Contains, Get};
use xcm::prelude::*;
use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset};
/// A `FeeManager` implementation that simply deposits the fees handled into a specific on-chain
/// `ReceiverAccount`.
///
/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets, and also
/// permits specifying `WaivedLocations` for locations that are privileged to not pay for fees. If
/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be
/// logged.
pub struct XcmFeesToAccount<XcmConfig, WaivedLocations, AccountId, ReceiverAccount>(
PhantomData<(XcmConfig, WaivedLocations, AccountId, ReceiverAccount)>,
);
impl<
XcmConfig: xcm_executor::Config,
WaivedLocations: Contains<MultiLocation>,
AccountId: Clone + Into<[u8; 32]>,
ReceiverAccount: Get<Option<AccountId>>,
> FeeManager for XcmFeesToAccount<XcmConfig, WaivedLocations, AccountId, ReceiverAccount>
{
fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool {
let Some(loc) = origin else { return false };
WaivedLocations::contains(loc)
}
fn handle_fee(fees: MultiAssets, context: Option<&XcmContext>) {
if let Some(receiver) = ReceiverAccount::get() {
let dest = AccountId32 { network: None, id: receiver.into() }.into();
for asset in fees.into_inner() {
if let Err(e) = XcmConfig::AssetTransactor::deposit_asset(&asset, &dest, context) {
log::trace!(
target: "xcm::fees",
"`AssetTransactor::deposit_asset` returned error: {:?}, burning fees: {:?}",
e, asset,
);
}
}
}
}
}
@@ -274,7 +274,11 @@ impl<
} }
} }
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> XcmResult { fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
_context: Option<&XcmContext>,
) -> XcmResult {
log::trace!( log::trace!(
target: "xcm::fungibles_adapter", target: "xcm::fungibles_adapter",
"deposit_asset what: {:?}, who: {:?}", "deposit_asset what: {:?}, who: {:?}",
@@ -371,7 +375,11 @@ impl<
>::check_out(dest, what, context) >::check_out(dest, what, context)
} }
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
FungiblesMutateAdapter::< FungiblesMutateAdapter::<
Assets, Assets,
Matcher, Matcher,
+3
View File
@@ -67,6 +67,9 @@ pub use process_xcm_message::ProcessXcmMessage;
mod currency_adapter; mod currency_adapter;
pub use currency_adapter::CurrencyAdapter; pub use currency_adapter::CurrencyAdapter;
mod fee_handling;
pub use fee_handling::XcmFeesToAccount;
mod fungibles_adapter; mod fungibles_adapter;
pub use fungibles_adapter::{ pub use fungibles_adapter::{
AssetChecking, DualMint, FungiblesAdapter, FungiblesMutateAdapter, FungiblesTransferAdapter, AssetChecking, DualMint, FungiblesAdapter, FungiblesMutateAdapter, FungiblesTransferAdapter,
@@ -207,7 +207,11 @@ impl<
} }
} }
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
log::trace!( log::trace!(
target: LOG_TARGET, target: LOG_TARGET,
"deposit_asset what: {:?}, who: {:?}, context: {:?}", "deposit_asset what: {:?}, who: {:?}, context: {:?}",
@@ -307,7 +311,11 @@ impl<
>::check_out(dest, what, context) >::check_out(dest, what, context)
} }
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
NonFungiblesMutateAdapter::< NonFungiblesMutateAdapter::<
Assets, Assets,
Matcher, Matcher,
+8 -5
View File
@@ -110,11 +110,14 @@ impl<
let message = Xcm(vec![ let message = Xcm(vec![
DescendOrigin(Interior::get()), DescendOrigin(Interior::get()),
UnpaidExecution { weight_limit: Unlimited, check_origin: None }, UnpaidExecution { weight_limit: Unlimited, check_origin: None },
SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { SetAppendix(Xcm(vec![
destination, SetFeesMode { jit_withdraw: true },
query_id, ReportError(QueryResponseInfo {
max_weight: Weight::zero(), destination,
})])), query_id,
max_weight: Weight::zero(),
}),
])),
TransferAsset { TransferAsset {
beneficiary, beneficiary,
assets: vec![MultiAsset { id: asset_id, fun: Fungibility::Fungible(amount) }] assets: vec![MultiAsset { id: asset_id, fun: Fungibility::Fungible(amount) }]
+2 -2
View File
@@ -253,7 +253,7 @@ impl TransactAsset for TestAssetTransactor {
fn deposit_asset( fn deposit_asset(
what: &MultiAsset, what: &MultiAsset,
who: &MultiLocation, who: &MultiLocation,
_context: &XcmContext, _context: Option<&XcmContext>,
) -> Result<(), XcmError> { ) -> Result<(), XcmError> {
add_asset(*who, what.clone()); add_asset(*who, what.clone());
Ok(()) Ok(())
@@ -526,7 +526,7 @@ impl FeeManager for TestFeeManager {
fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool { fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool {
IS_WAIVED.with(|l| l.borrow().contains(&r)) IS_WAIVED.with(|l| l.borrow().contains(&r))
} }
fn handle_fee(_: MultiAssets) {} fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {}
} }
#[derive(Clone, Eq, PartialEq, Debug)] #[derive(Clone, Eq, PartialEq, Debug)]
+16 -10
View File
@@ -71,11 +71,14 @@ fn pay_over_xcm_works() {
let expected_message = Xcm(vec![ let expected_message = Xcm(vec![
DescendOrigin(AccountId32 { id: SenderAccount::get().into(), network: None }.into()), DescendOrigin(AccountId32 { id: SenderAccount::get().into(), network: None }.into()),
UnpaidExecution { weight_limit: Unlimited, check_origin: None }, UnpaidExecution { weight_limit: Unlimited, check_origin: None },
SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { SetAppendix(Xcm(vec![
destination: (Parent, Parachain(42)).into(), SetFeesMode { jit_withdraw: true },
query_id: 1, ReportError(QueryResponseInfo {
max_weight: Weight::zero(), destination: (Parent, Parachain(42)).into(),
})])), query_id: 1,
max_weight: Weight::zero(),
}),
])),
TransferAsset { TransferAsset {
assets: (Here, amount).into(), assets: (Here, amount).into(),
beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(),
@@ -130,11 +133,14 @@ fn pay_over_xcm_governance_body() {
let expected_message = Xcm(vec![ let expected_message = Xcm(vec![
DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()), DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()),
UnpaidExecution { weight_limit: Unlimited, check_origin: None }, UnpaidExecution { weight_limit: Unlimited, check_origin: None },
SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { SetAppendix(Xcm(vec![
destination: (Parent, Parachain(42)).into(), SetFeesMode { jit_withdraw: true },
query_id: 1, ReportError(QueryResponseInfo {
max_weight: Weight::zero(), destination: (Parent, Parachain(42)).into(),
})])), query_id: 1,
max_weight: Weight::zero(),
}),
])),
TransferAsset { TransferAsset {
assets: (Parent, amount).into(), assets: (Parent, amount).into(),
beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(),
@@ -148,11 +148,14 @@ fn salary_pay_over_xcm_works() {
let expected_message: Xcm<RuntimeCall> = Xcm::<RuntimeCall>(vec![ let expected_message: Xcm<RuntimeCall> = Xcm::<RuntimeCall>(vec![
DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()), DescendOrigin(Plurality { id: BodyId::Treasury, part: BodyPart::Voice }.into()),
UnpaidExecution { weight_limit: Unlimited, check_origin: None }, UnpaidExecution { weight_limit: Unlimited, check_origin: None },
SetAppendix(Xcm(vec![ReportError(QueryResponseInfo { SetAppendix(Xcm(vec![
destination: (Parent, Parachain(42)).into(), SetFeesMode { jit_withdraw: true },
query_id: 1, ReportError(QueryResponseInfo {
max_weight: Weight::zero(), destination: (Parent, Parachain(42)).into(),
})])), query_id: 1,
max_weight: Weight::zero(),
}),
])),
TransferAsset { TransferAsset {
assets: (AssetHubAssetId::get(), FixedSalaryAmount::get()).into(), assets: (AssetHubAssetId::get(), FixedSalaryAmount::get()).into(),
beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(), beneficiary: AccountId32 { id: recipient.clone().into(), network: None }.into(),
+2 -2
View File
@@ -171,13 +171,13 @@ pub type Barrier = (
); );
parameter_types! { parameter_types! {
pub KusamaForStatemine: (MultiAssetFilter, MultiLocation) = pub KusamaForAssetHub: (MultiAssetFilter, MultiLocation) =
(Wild(AllOf { id: Concrete(Here.into()), fun: WildFungible }), Parachain(1000).into()); (Wild(AllOf { id: Concrete(Here.into()), fun: WildFungible }), Parachain(1000).into());
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 4; pub const MaxAssetsIntoHolding: u32 = 4;
} }
pub type TrustedTeleporters = (xcm_builder::Case<KusamaForStatemine>,); pub type TrustedTeleporters = (xcm_builder::Case<KusamaForAssetHub>,);
pub struct XcmConfig; pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig { impl xcm_executor::Config for XcmConfig {
+6 -6
View File
@@ -174,7 +174,7 @@ fn report_holding_works() {
} }
/// Scenario: /// Scenario:
/// A parachain wants to move KSM from Kusama to Statemine. /// A parachain wants to move KSM from Kusama to Asset Hub.
/// The parachain sends an XCM to withdraw funds combined with a teleport to the destination. /// The parachain sends an XCM to withdraw funds combined with a teleport to the destination.
/// ///
/// This way of moving funds from a relay to a parachain will only work for trusted chains. /// This way of moving funds from a relay to a parachain will only work for trusted chains.
@@ -182,12 +182,12 @@ fn report_holding_works() {
/// ///
/// Asserts that the balances are updated accordingly and the correct XCM is sent. /// Asserts that the balances are updated accordingly and the correct XCM is sent.
#[test] #[test]
fn teleport_to_statemine_works() { fn teleport_to_asset_hub_works() {
use xcm::opaque::latest::prelude::*; use xcm::opaque::latest::prelude::*;
let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating(); let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating();
let balances = vec![(ALICE, INITIAL_BALANCE), (para_acc.clone(), INITIAL_BALANCE)]; let balances = vec![(ALICE, INITIAL_BALANCE), (para_acc.clone(), INITIAL_BALANCE)];
kusama_like_with_balances(balances).execute_with(|| { kusama_like_with_balances(balances).execute_with(|| {
let statemine_id = 1000; let asset_hub_id = 1000;
let other_para_id = 3000; let other_para_id = 3000;
let amount = REGISTER_AMOUNT; let amount = REGISTER_AMOUNT;
let teleport_effects = vec![ let teleport_effects = vec![
@@ -222,13 +222,13 @@ fn teleport_to_statemine_works() {
vec![(Parachain(other_para_id).into(), expected_msg, expected_hash,)] vec![(Parachain(other_para_id).into(), expected_msg, expected_hash,)]
); );
// teleports are allowed from statemine to kusama. // teleports are allowed from asset hub to kusama.
let message = Xcm(vec![ let message = Xcm(vec![
WithdrawAsset((Here, amount).into()), WithdrawAsset((Here, amount).into()),
buy_execution(), buy_execution(),
InitiateTeleport { InitiateTeleport {
assets: All.into(), assets: All.into(),
dest: Parachain(statemine_id).into(), dest: Parachain(asset_hub_id).into(),
xcm: Xcm(teleport_effects.clone()), xcm: Xcm(teleport_effects.clone()),
}, },
]); ]);
@@ -246,7 +246,7 @@ fn teleport_to_statemine_works() {
mock::sent_xcm(), mock::sent_xcm(),
vec![ vec![
(Parachain(other_para_id).into(), expected_msg.clone(), expected_hash,), (Parachain(other_para_id).into(), expected_msg.clone(), expected_hash,),
(Parachain(statemine_id).into(), expected_msg, expected_hash,) (Parachain(asset_hub_id).into(), expected_msg, expected_hash,)
] ]
); );
}); });
+18 -14
View File
@@ -248,7 +248,7 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
for asset in fees.inner() { for asset in fees.inner() {
Config::AssetTransactor::withdraw_asset(&asset, &origin, None)?; Config::AssetTransactor::withdraw_asset(&asset, &origin, None)?;
} }
Config::FeeManager::handle_fee(fees); Config::FeeManager::handle_fee(fees, None);
} }
Ok(()) Ok(())
} }
@@ -405,10 +405,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
reason: FeeReason, reason: FeeReason,
) -> Result<XcmHash, XcmError> { ) -> Result<XcmHash, XcmError> {
let (ticket, fee) = validate_send::<Config::XcmSender>(dest, msg)?; let (ticket, fee) = validate_send::<Config::XcmSender>(dest, msg)?;
if !Config::FeeManager::is_waived(self.origin_ref(), reason) { self.take_fee(fee, reason)?;
let paid = self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?;
Config::FeeManager::handle_fee(paid.into());
}
Config::XcmSender::deliver(ticket).map_err(Into::into) Config::XcmSender::deliver(ticket).map_err(Into::into)
} }
@@ -618,14 +615,18 @@ impl<Config: config::Config> XcmExecutor<Config> {
DepositAsset { assets, beneficiary } => { DepositAsset { assets, beneficiary } => {
let deposited = self.holding.saturating_take(assets); let deposited = self.holding.saturating_take(assets);
for asset in deposited.into_assets_iter() { for asset in deposited.into_assets_iter() {
Config::AssetTransactor::deposit_asset(&asset, &beneficiary, &self.context)?; Config::AssetTransactor::deposit_asset(
&asset,
&beneficiary,
Some(&self.context),
)?;
} }
Ok(()) Ok(())
}, },
DepositReserveAsset { assets, dest, xcm } => { DepositReserveAsset { assets, dest, xcm } => {
let deposited = self.holding.saturating_take(assets); let deposited = self.holding.saturating_take(assets);
for asset in deposited.assets_iter() { for asset in deposited.assets_iter() {
Config::AssetTransactor::deposit_asset(&asset, &dest, &self.context)?; Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?;
} }
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot // Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot
// be reanchored because we have already called `deposit_asset` on all assets. // be reanchored because we have already called `deposit_asset` on all assets.
@@ -944,6 +945,14 @@ impl<Config: config::Config> XcmExecutor<Config> {
if Config::FeeManager::is_waived(self.origin_ref(), reason) { if Config::FeeManager::is_waived(self.origin_ref(), reason) {
return Ok(()) return Ok(())
} }
log::trace!(
target: "xcm::fees",
"taking fee: {:?} from origin_ref: {:?} in fees_mode: {:?} for a reason: {:?}",
fee,
self.origin_ref(),
self.fees_mode,
reason,
);
let paid = if self.fees_mode.jit_withdraw { let paid = if self.fees_mode.jit_withdraw {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
for asset in fee.inner() { for asset in fee.inner() {
@@ -953,7 +962,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
} else { } else {
self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into() self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into()
}; };
Config::FeeManager::handle_fee(paid); Config::FeeManager::handle_fee(paid, Some(&self.context));
Ok(()) Ok(())
} }
@@ -985,12 +994,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
let QueryResponseInfo { destination, query_id, max_weight } = info; let QueryResponseInfo { destination, query_id, max_weight } = info;
let instruction = QueryResponse { query_id, response, max_weight, querier }; let instruction = QueryResponse { query_id, response, max_weight, querier };
let message = Xcm(vec![instruction]); let message = Xcm(vec![instruction]);
let (ticket, fee) = validate_send::<Config::XcmSender>(destination, message)?; self.send(destination, message, fee_reason)
if !Config::FeeManager::is_waived(self.origin_ref(), fee_reason) {
let paid = self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?;
Config::FeeManager::handle_fee(paid.into());
}
Config::XcmSender::deliver(ticket).map_err(Into::into)
} }
fn try_reanchor( fn try_reanchor(
@@ -23,11 +23,11 @@ pub trait FeeManager {
/// Do something with the fee which has been paid. Doing nothing here silently burns the /// Do something with the fee which has been paid. Doing nothing here silently burns the
/// fees. /// fees.
fn handle_fee(fee: MultiAssets); fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>);
} }
/// Context under which a fee is paid. /// Context under which a fee is paid.
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FeeReason { pub enum FeeReason {
/// When a reporting instruction is called. /// When a reporting instruction is called.
Report, Report,
@@ -53,7 +53,7 @@ pub enum FeeReason {
impl FeeManager for () { impl FeeManager for () {
fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool { fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool {
true false
} }
fn handle_fee(_: MultiAssets) {} fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {}
} }
@@ -87,7 +87,11 @@ pub trait TransactAsset {
/// Deposit the `what` asset into the account of `who`. /// Deposit the `what` asset into the account of `who`.
/// ///
/// Implementations should return `XcmError::FailedToTransactAsset` if deposit failed. /// Implementations should return `XcmError::FailedToTransactAsset` if deposit failed.
fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation, _context: &XcmContext) -> XcmResult { fn deposit_asset(
_what: &MultiAsset,
_who: &MultiLocation,
_context: Option<&XcmContext>,
) -> XcmResult {
Err(XcmError::Unimplemented) Err(XcmError::Unimplemented)
} }
@@ -139,7 +143,7 @@ pub trait TransactAsset {
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => { Err(XcmError::AssetNotFound | XcmError::Unimplemented) => {
let assets = Self::withdraw_asset(asset, from, Some(context))?; let assets = Self::withdraw_asset(asset, from, Some(context))?;
// Not a very forgiving attitude; once we implement roll-backs then it'll be nicer. // Not a very forgiving attitude; once we implement roll-backs then it'll be nicer.
Self::deposit_asset(asset, to, context)?; Self::deposit_asset(asset, to, Some(context))?;
Ok(assets) Ok(assets)
}, },
result => result, result => result,
@@ -195,7 +199,11 @@ impl TransactAsset for Tuple {
)* ); )* );
} }
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { fn deposit_asset(
what: &MultiAsset,
who: &MultiLocation,
context: Option<&XcmContext>,
) -> XcmResult {
for_tuples!( #( for_tuples!( #(
match Tuple::deposit_asset(what, who, context) { match Tuple::deposit_asset(what, who, context) {
Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (),
@@ -286,7 +294,7 @@ mod tests {
fn deposit_asset( fn deposit_asset(
_what: &MultiAsset, _what: &MultiAsset,
_who: &MultiLocation, _who: &MultiLocation,
_context: &XcmContext, _context: Option<&XcmContext>,
) -> XcmResult { ) -> XcmResult {
Err(XcmError::AssetNotFound) Err(XcmError::AssetNotFound)
} }
@@ -330,7 +338,7 @@ mod tests {
fn deposit_asset( fn deposit_asset(
_what: &MultiAsset, _what: &MultiAsset,
_who: &MultiLocation, _who: &MultiLocation,
_context: &XcmContext, _context: Option<&XcmContext>,
) -> XcmResult { ) -> XcmResult {
Err(XcmError::Overflow) Err(XcmError::Overflow)
} }
@@ -374,7 +382,7 @@ mod tests {
fn deposit_asset( fn deposit_asset(
_what: &MultiAsset, _what: &MultiAsset,
_who: &MultiLocation, _who: &MultiLocation,
_context: &XcmContext, _context: Option<&XcmContext>,
) -> XcmResult { ) -> XcmResult {
Ok(()) Ok(())
} }
@@ -406,7 +414,7 @@ mod tests {
MultiTransactor::deposit_asset( MultiTransactor::deposit_asset(
&(Here, 1u128).into(), &(Here, 1u128).into(),
&Here.into(), &Here.into(),
&XcmContext::with_message_id([0; 32]), Some(&XcmContext::with_message_id([0; 32])),
), ),
Err(XcmError::AssetNotFound) Err(XcmError::AssetNotFound)
); );
@@ -420,7 +428,7 @@ mod tests {
MultiTransactor::deposit_asset( MultiTransactor::deposit_asset(
&(Here, 1u128).into(), &(Here, 1u128).into(),
&Here.into(), &Here.into(),
&XcmContext::with_message_id([0; 32]), Some(&XcmContext::with_message_id([0; 32])),
), ),
Ok(()) Ok(())
); );
@@ -434,7 +442,7 @@ mod tests {
MultiTransactor::deposit_asset( MultiTransactor::deposit_asset(
&(Here, 1u128).into(), &(Here, 1u128).into(),
&Here.into(), &Here.into(),
&XcmContext::with_message_id([0; 32]), Some(&XcmContext::with_message_id([0; 32])),
), ),
Err(XcmError::Overflow) Err(XcmError::Overflow)
); );
@@ -448,7 +456,7 @@ mod tests {
MultiTransactor::deposit_asset( MultiTransactor::deposit_asset(
&(Here, 1u128).into(), &(Here, 1u128).into(),
&Here.into(), &Here.into(),
&XcmContext::with_message_id([0; 32]), Some(&XcmContext::with_message_id([0; 32])),
), ),
Ok(()), Ok(()),
); );
+20
View File
@@ -0,0 +1,20 @@
# Schema: Parity PR Documentation Schema (prdoc)
# See doc at https://github.com/paritytech/prdoc
title: Introduce XcmFeesToAccount fee manager
doc:
- audience: Builder
description: |
Now all XCM sending, unless done by the system for the system, will be charged delivery fees.
All runtimes are now configured to send these delivery fees to a treasury account.
The fee formula is `delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee)`.
migrations:
db: []
runtime: []
crates: []
host_functions: []
@@ -33,8 +33,9 @@ pub(crate) fn weight_witness_warning(
if dev_mode { if dev_mode {
return return
} }
let CallWeightDef::Immediate(w) = &method.weight else {
let CallWeightDef::Immediate(w) = &method.weight else { return }; return
};
let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") let partial_warning = Warning::new_deprecated("UncheckedWeightWitness")
.old("not check weight witness data") .old("not check weight witness data")
@@ -65,8 +66,9 @@ pub(crate) fn weight_constant_warning(
if dev_mode { if dev_mode {
return return
} }
let syn::Expr::Lit(lit) = weight else {
let syn::Expr::Lit(lit) = weight else { return }; return
};
let warning = Warning::new_deprecated("ConstantWeight") let warning = Warning::new_deprecated("ConstantWeight")
.index(warnings.len()) .index(warnings.len())