Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion pallets/parachain-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use sp_runtime::{
InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity,
ValidTransaction,
},
FixedU128, Saturating,
};
use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
use xcm::latest::XcmHash;
Expand Down Expand Up @@ -91,6 +92,8 @@ pub use relay_state_snapshot::{MessagingStateSnapshot, RelayChainStateProof};

pub use pallet::*;

pub const MULTIPLICATIVE_FEE_FACTOR_UMP: FixedU128 = FixedU128::from_rational(101, 100); // 1.01

/// Something that can check the associated relay block number.
///
/// Each Parachain block is built in the context of a relay chain block, this trait allows us
Expand Down Expand Up @@ -261,6 +264,9 @@ pub mod pallet {

UpwardMessages::<T>::put(&up[..num]);
*up = up.split_off(num);
if num > 0 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should check whether the UMP queue is less than then max limit.

Self::decrement_ump_fee_factor();
}
});

// Sending HRMP messages is a little bit more involved. There are the following
Expand Down Expand Up @@ -691,6 +697,16 @@ pub mod pallet {
#[pallet::storage]
pub(super) type CustomValidationHeadData<T: Config> = StorageValue<_, Vec<u8>, OptionQuery>;

frame_support::parameter_types! {
pub InitialFactor: FixedU128 = FixedU128::from_u32(1);
}

/// The number to multiply the base delivery fee by.
#[pallet::storage]
#[pallet::getter(fn delivery_fee_factor_ump)]
pub(crate) type DeliveryFeeFactorUmp<T: Config> =
StorageValue<_, FixedU128, ValueQuery, InitialFactor>;

#[pallet::inherent]
impl<T: Config> ProvideInherent for Pallet<T> {
type Call = Call<T>;
Expand Down Expand Up @@ -1069,7 +1085,7 @@ impl<T: Config> Pallet<T> {
match Self::host_configuration() {
Some(cfg) =>
if message.len() > cfg.max_upward_message_size as usize {
return Err(MessageSendError::TooBig)
Self::increment_ump_fee_factor();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the wrong place to put the increment. The condition here checks whether the individual message size is greater than the limit, and does not check for the queue size.

},
None => {
// This storage field should carry over from the previous block. So if it's None
Expand All @@ -1091,6 +1107,28 @@ impl<T: Config> Pallet<T> {
Self::deposit_event(Event::UpwardMessageSent { message_hash: Some(hash) });
Ok((0, hash))
}

/// Raise the delivery fee factor by a multiplicative factor and stores the resulting value.
///
/// Returns the new delivery fee factor after the increment.
pub(crate) fn increment_ump_fee_factor() -> FixedU128 {
<DeliveryFeeFactorUMP<T>>::mutate(|f| {
*f = f.saturating_mul(MULTIPLICATIVE_FEE_FACTOR_UMP);
*f
})
}

/// Reduce the delivery fee factor by a multiplicative factor and stores the resulting value.
///
/// 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_ump_fee_factor() -> FixedU128 {
<DeliveryFeeFactorUMP<T>>::mutate(|f| {
*f = InitialFactor::get().max(*f / MULTIPLICATIVE_FEE_FACTOR_UMP);
*f
})
}
}

impl<T: Config> UpwardMessageSender for Pallet<T> {
Expand Down
59 changes: 57 additions & 2 deletions pallets/xcmp-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use rand_chacha::{
ChaChaRng,
};
use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug;
use sp_runtime::{FixedPointNumber, FixedU128, RuntimeDebug, Saturating};
use sp_std::{convert::TryFrom, prelude::*};
use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH};
use xcm_executor::traits::ConvertOrigin;
Expand All @@ -72,6 +72,8 @@ const MAX_MESSAGES_PER_BLOCK: u8 = 10;
// Maximum amount of messages that can exist in the overweight queue at any given time.
const MAX_OVERWEIGHT_MESSAGES: u32 = 1000;

pub const MULTIPLICATIVE_FEE_FACTOR_XCMP: FixedU128 = FixedU128::from_rational(101, 100); // 1.01

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -374,6 +376,16 @@ pub mod pallet {
/// Whether or not the XCMP queue is suspended from executing incoming XCMs or not.
#[pallet::storage]
pub(super) type QueueSuspended<T: Config> = StorageValue<_, bool, ValueQuery>;

frame_support::parameter_types! {
pub InitialFactor: FixedU128 = FixedU128::from_u32(1);
}

/// The number to multiply the base delivery fee by.
#[pallet::storage]
#[pallet::getter(fn delivery_fee_factor_xcmp)]
pub(crate) type DeliveryFeeFactor<T: Config> =
StorageValue<_, FixedU128, ValueQuery, InitialFactor>;
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)]
Expand Down Expand Up @@ -516,7 +528,7 @@ impl<T: Config> Pallet<T> {
let max_message_size =
T::ChannelInfo::get_channel_max(recipient).ok_or(MessageSendError::NoChannel)?;
if data.len() > max_message_size {
return Err(MessageSendError::TooBig)
Self::increment_xcmp_fee_factor();
}

let mut s = <OutboundXcmpStatus<T>>::get();
Expand Down Expand Up @@ -943,6 +955,28 @@ impl<T: Config> Pallet<T> {
}
});
}

/// Raise the delivery fee factor by a multiplicative factor and stores the resulting value.
///
/// Returns the new delivery fee factor after the increment.
pub(crate) fn increment_xcmp_fee_factor() -> FixedU128 {
<DeliveryFeeFactorXCMP<T>>::mutate(|f| {
*f = f.saturating_mul(MULTIPLICATIVE_FEE_FACTOR_XCMP);
*f
})
}

/// Reduce the delivery fee factor by a multiplicative factor and stores the resulting value.
///
/// 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_xcmp_fee_factor() -> FixedU128 {
<DeliveryFeeFactorXCMP<T>>::mutate(|f| {
*f = InitialFactor::get().max(*f / MULTIPLICATIVE_FEE_FACTOR_XCMP);
*f
})
}
}

impl<T: Config> XcmpMessageHandler for Pallet<T> {
Expand Down Expand Up @@ -1129,6 +1163,9 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {

<OutboundXcmpStatus<T>>::put(statuses);

if !result.is_empty() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should check whether the number of messages in queue is less than the maximum limit.

Self::decrement_xcmp_fee_factor();
}
result
}
}
Expand Down Expand Up @@ -1190,3 +1227,21 @@ impl<T: Config> SendXcm for Pallet<T> {
}
}
}

/// Implementation of `PriceForSiblingDelivery` 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
/// by a specified factor. In mathematical form, it is `F * (B + msg_len * M)`.
pub struct SiblingExponentialPrice<A, B, M, F>(sp_std::marker::PhantomData<(A, B, M, F)>);
impl<A: Get<AssetId>, B: Get<u128>, M: Get<u128>, F: Get<FixedU128>> PriceForSiblingDelivery
for SiblingExponentialPrice<A, B, M, F>
{
fn price_for_sibling_delivery(_para_id: ParaId, msg: &Xcm<()>) -> MultiAssets {
let msg_fee = (msg.encoded_size() as u128).saturating_mul(M::get());
let fee_sum = B::get().saturating_add(msg_fee);
let amount = F::get().saturating_mul_int(fee_sum);
(A::get(), amount).into()
}
}
23 changes: 22 additions & 1 deletion parachains/common/src/xcm_config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::impls::AccountIdOf;
use core::{marker::PhantomData, ops::ControlFlow};
use cumulus_primitives_utility::PriceForParentDelivery;
use frame_support::{
log,
traits::{fungibles::Inspect, tokens::BalanceConversion, ContainsPair},
weights::{Weight, WeightToFee, WeightToFeePolynomial},
};
use sp_runtime::traits::Get;
use sp_core::Encode;
use sp_runtime::{traits::Get, FixedPointNumber, FixedU128};
use xcm::{latest::prelude::*, CreateMatcher, MatchXcm};
use xcm_executor::traits::ShouldExecute;

Expand Down Expand Up @@ -134,3 +136,22 @@ impl<Location: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation>
matches!(asset.id, Concrete(ref id) if id == origin && origin == &Location::get())
}
}

//TODO: just reference this from polkadot once https://github.com/paritytech/polkadot/pull/6843 merges
/// Implementation of `PriceForParentDelivery` 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
/// by a specified factor. In mathematical form, it is `F * (B + msg_len * M)`.
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: Get<FixedU128>> PriceForParentDelivery
for ExponentialPrice<A, B, M, F>
{
fn price_for_parent_delivery(msg: &Xcm<()>) -> MultiAssets {
let msg_fee = (msg.encoded_size() as u128).saturating_mul(M::get());
let fee_sum = B::get().saturating_add(msg_fee);
let amount = F::get().saturating_mul_int(fee_sum);
(A::get(), amount).into()
}
}
5 changes: 4 additions & 1 deletion parachains/runtimes/assets/statemine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ pub mod constants;
mod weights;
pub mod xcm_config;

use crate::xcm_config::{BaseDeliveryFee, FeeAssetId, XcmpFeeFactor};
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_pallet_xcmp_queue::SiblingExponentialPrice;
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
Expand Down Expand Up @@ -475,7 +477,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
>;
type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin;
type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo<Runtime>;
type PriceForSiblingDelivery = ();
type PriceForSiblingDelivery =
SiblingExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, XcmpFeeFactor>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when paritytech/polkadot#7005 and paritytech/polkadot#7585,
I am goging to reuse here lots of stuff from runtime/common e.g. ExponentialPrice / PriceForParachainDelivery ...

}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
23 changes: 21 additions & 2 deletions parachains/runtimes/assets/statemine/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use super::{
ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use crate::{TransactionByteFee, CENTS};
use frame_support::{
match_types, parameter_types,
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
Expand All @@ -27,10 +28,11 @@ use parachains_common::{
impls::ToStakingPot,
xcm_config::{
AssetFeeAsExistentialDepositMultiplier, DenyReserveTransferToRelayChain, DenyThenTry,
ExponentialPrice,
},
};
use polkadot_parachain::primitives::Sibling;
use sp_runtime::traits::ConvertInto;
use sp_runtime::{traits::ConvertInto, FixedU128};
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
Expand Down Expand Up @@ -129,6 +131,19 @@ pub type XcmOriginToTransactDispatchOrigin = (

parameter_types! {
pub const MaxInstructions: u32 = 100;

/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(Here.into());

/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);

/// The factor to multiply by for the message delivery fees.
pub UmpFeeFactor: FixedU128 = ParachainSystem::delivery_fee_factor_ump();

/// The factor to multiply by for the message delivery fees.
pub XcmpFeeFactor: FixedU128 = XcmpQueue::delivery_fee_factor_xcmp();

pub const MaxAssetsIntoHolding: u32 = 64;
pub XcmAssetFeesReceiver: Option<AccountId> = Authorship::author();
}
Expand Down Expand Up @@ -326,7 +341,11 @@ pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, R
/// queues.
pub type XcmRouter = (
// Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, ()>,
cumulus_primitives_utility::ParentAsUmp<
ParachainSystem,
PolkadotXcm,
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, UmpFeeFactor>,
>,
// ..and XCMP to communicate with the sibling chains.
XcmpQueue,
);
Expand Down
4 changes: 0 additions & 4 deletions primitives/utility/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@ impl<T: Get<MultiAssets>> PriceForParentDelivery for ConstantPrice<T> {
/// 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
/// `UpwardMessageSender` trait impl into a `SendXcm` trait impl.
///
/// NOTE: This is a pretty dumb "just send it" router; we will probably want to introduce queuing
/// to UMP eventually and when we do, the pallet which implements the queuing will be responsible
/// for the `SendXcm` implementation.
pub struct ParentAsUmp<T, W, P>(PhantomData<(T, W, P)>);
impl<T, W, P> SendXcm for ParentAsUmp<T, W, P>
where
Expand Down