Skip to content

Commit

Permalink
Add UMP pricing (#1556)
Browse files Browse the repository at this point in the history
# Description

Adds pricing for UMP, much like it was added for DMP in
paritytech/polkadot#6843 and HRMP in
#1234.

---------

Co-authored-by: command-bot <>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
  • Loading branch information
3 people authored Oct 12, 2023
1 parent 18bcdec commit 73ad0fc
Show file tree
Hide file tree
Showing 45 changed files with 824 additions and 250 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cumulus/pallets/parachain-system/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ sp-version = { path = "../../../substrate/primitives/version", default-features

# Polkadot
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}

# Cumulus
Expand Down Expand Up @@ -63,6 +64,7 @@ std = [
"frame-system/std",
"log/std",
"polkadot-parachain-primitives/std",
"polkadot-runtime-parachains/std",
"scale-info/std",
"sp-core/std",
"sp-externalities/std",
Expand All @@ -80,12 +82,14 @@ runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]

try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"polkadot-runtime-parachains/try-runtime",
"sp-runtime/try-runtime",
]

Expand Down
90 changes: 87 additions & 3 deletions cumulus/pallets/parachain-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ use frame_support::{
};
use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor};
use polkadot_parachain_primitives::primitives::RelayChainBlockNumber;
use polkadot_runtime_parachains::FeeTracker;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{Block as BlockT, BlockNumberProvider, Hash},
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity,
ValidTransaction,
},
DispatchError, RuntimeDebug,
DispatchError, FixedU128, RuntimeDebug, Saturating,
};
use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
use xcm::latest::XcmHash;
Expand Down Expand Up @@ -177,6 +178,20 @@ where
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]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -240,6 +255,9 @@ pub mod pallet {

#[pallet::hooks]
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`]).
fn on_finalize(_: BlockNumberFor<T>) {
<DidSetValidationCode<T>>::kill();
<UpgradeRestrictionSignal<T>>::kill();
Expand Down Expand Up @@ -326,6 +344,17 @@ pub mod pallet {
UpwardMessages::<T>::put(&up[..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)
});

Expand Down Expand Up @@ -721,7 +750,7 @@ pub mod pallet {
StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;

/// 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.
#[pallet::storage]
pub(super) type AggregatedUnincludedSegment<T: Config> =
Expand Down Expand Up @@ -860,6 +889,17 @@ pub mod pallet {
pub(super) type PendingUpwardMessages<T: Config> =
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
/// announcing the weight of `on_initialize` and `on_finalize`.
#[pallet::storage]
Expand Down Expand Up @@ -976,6 +1016,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> {
fn get_channel_status(id: ParaId) -> ChannelStatus {
// Note, that we are using `relevant_messaging_state` which may be from the previous
Expand Down Expand Up @@ -1468,7 +1533,13 @@ impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<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> {
let message_len = message.len();
// Check if the message fits into the relay-chain constraints.
//
// Note, that we are using `host_configuration` here which may be from the previous
Expand All @@ -1482,9 +1553,21 @@ impl<T: Config> Pallet<T> {
//
// However, changing this setting is expected to be rare.
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)
}
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.
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 {
// 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
Expand All @@ -1496,6 +1579,7 @@ impl<T: Config> Pallet<T> {
//
// Thus fall through here.
};

<PendingUpwardMessages<T>>::append(message.clone());

// The relay ump does not use using_encoded
Expand Down
48 changes: 21 additions & 27 deletions cumulus/pallets/xcmp-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use frame_support::{
traits::{EnsureOrigin, Get},
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::{
rand_core::{RngCore, SeedableRng},
Expand Down Expand Up @@ -110,7 +110,7 @@ pub mod pallet {
type ControllerOriginConverter: ConvertOrigin<Self::RuntimeOrigin>;

/// 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.
type WeightInfo: WeightInfo;
Expand Down Expand Up @@ -970,28 +970,6 @@ impl<T: Config> Pallet<T> {
}
});
}

/// Increases the delivery fee factor by a multiplicative factor and stores the resulting value.
///
/// Returns the new delivery fee factor after the increase.
pub(crate) fn increase_fee_factor(para: ParaId, message_size_factor: FixedU128) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(para, |f| {
*f = f.saturating_mul(EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor));
*f
})
}

/// Decreases 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 decrease.
pub(crate) fn decrease_fee_factor(para: ParaId) -> FixedU128 {
<DeliveryFeeFactor<T>>::mutate(para, |f| {
*f = InitialFactor::get().max(*f / EXPONENTIAL_FEE_BASE);
*f
})
}
}

impl<T: Config> XcmpMessageHandler for Pallet<T> {
Expand Down Expand Up @@ -1203,7 +1181,7 @@ impl<T: Config> SendXcm for Pallet<T> {
MultiLocation { parents: 1, interior: X1(Parachain(id)) } => {
let xcm = msg.take().ok_or(SendError::MissingArgument)?;
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)
.map_err(|()| SendError::DestinationUnsupported)?;
Ok(((id, versioned_xcm), price))
Expand Down Expand Up @@ -1231,7 +1209,23 @@ impl<T: Config> SendXcm for Pallet<T> {
}

impl<T: Config> FeeTracker for Pallet<T> {
fn get_fee_factor(para: ParaId) -> FixedU128 {
<DeliveryFeeFactor<T>>::get(para)
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(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 / EXPONENTIAL_FEE_BASE);
*f
})
}
}
3 changes: 2 additions & 1 deletion cumulus/pallets/xcmp-queue/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use frame_support::{
traits::{ConstU32, Everything, Nothing, OriginTrait},
};
use frame_system::EnsureRoot;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
Expand Down Expand Up @@ -205,7 +206,7 @@ impl Config for Test {
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = SystemParachainAsSuperuser<RuntimeOrigin>;
type WeightInfo = ();
type PriceForSiblingDelivery = ();
type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
}

pub fn new_test_ext() -> sp_io::TestExternalities {
Expand Down
4 changes: 3 additions & 1 deletion cumulus/parachain-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mod weights;
pub mod xcm_config;

use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use cumulus_primitives_core::ParaId;
use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
use smallvec::smallvec;
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
Expand Down Expand Up @@ -412,7 +414,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = ();
type PriceForSiblingDelivery = ();
type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../../../../polk
xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../polkadot/xcm/xcm-executor", 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
parachains-common = { path = "../../../../common" }
Expand Down
Loading

0 comments on commit 73ad0fc

Please sign in to comment.