mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 19:51:05 +00:00
XCM v3 Companion (#697)
* Fixes * Undiener * Undiener * Undiener * Lockfile * Changes for send returning hash * Include message ID as params to execute_xcm * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Companion fixes * Formatting * Fixes * Formatting * Bump * Bump * Fixes * Formatting * Make the price of UMP/XCMP message sending configurable * cargo fmt * Remove InvertLocation * Formatting * Use ConstantPrice from polkadot-runtime-common * Fix naming * cargo fmt * Fixes * Fixes * Fixes * Add CallDispatcher * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Remove unused import * Remove unused import * XCMv3 fixes (#1710) * Fixes XCMv3 related Fixes XCMv3 (removed query_holding) Fixes XCMv3 - should use _depositable_count? Fixes XCMv3 - removed TrustedReserve Fixes - missing weights for statemine/statemint/westmint [DO-NOT-CHERRY-PICK] tmp return query_holding to aviod conficts to master Fixes - missing functions for pallet_xcm_benchmarks::generic::Config Fixes for XCMv3 benchmarking Fix xcm - removed query_holding * ".git/.scripts/bench-bot.sh" xcm statemine assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" xcm statemint assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" xcm westmint assets pallet_xcm_benchmarks::generic * Fix imports * Avoid consuming XCM message for NotApplicable scenario (#1787) * Avoid consuming message for NotApplicable scenario * Avoid consuming message for NotApplicable scenario tests * Add 10 message processing limit to DMP queue * Add 10 message limit to XCMP queue * Always increment the message_processed count whenever a message is processed * Fix formatting * Set an upper limit to the overweight message DMP queue * Add upper limit to XCMP overweight message queue * Fix for missing weight for `fn unpaid_execution()` * Fix - usage of `messages_processed` * Fixes * Fixes * Fixes * cargo fmt * Fixes * Fixes * Fixes * Fixes * Remove unused import * Fixes for gav-xcm-v3 (#1835) * Fix for FungiblesAdapter - trait changes: Contains -> AssetChecking * Fix for missing weight for `fn unpaid_execution()` * Used NonLocalMint for all NonZeroIssuance * Fix * Fixes * Fixes * Fixes * Fixes * Fixes * Fix tests * Fixes * Add SafeCallFilter * Add missing config items * Add TODO * Use () as the PriceForParentDelivery * Fixes * Fixes * Fixes * Fixes * Update transact_origin to transact_origin_and_runtime_call * Add ReachableDest config item to XCM pallet * Update SafeCallFilter to allow remark_with_event in runtime benchmarks * cargo fmt * Update substrate * Fix worst_case_holding * Fix DMQ queue unit tests * Remove unused label * cargo fmt * Actually process incoming XCMs * Fixes * Fixes * Fixes * Fixes - return back Weightless * Added measured benchmarks for `pallet_xcm` (#1968) * Fix Fix Fix * Fix * Fixes for transact benchmark * Fixes add pallet_xcm to benchmarks * Revert remark_with_event * ".git/.scripts/bench-bot.sh" xcm statemine assets pallet_xcm_benchmarks::generic * Fixes * TMP * Fix for reserve_asset_deposited * ".git/.scripts/bench-bot.sh" pallet statemine assets pallet_xcm * Fix * ".git/.scripts/bench-bot.sh" pallet statemint assets pallet_xcm * Fix * ".git/.scripts/bench-bot.sh" pallet westmint assets pallet_xcm * Fix westmint * ".git/.scripts/bench-bot.sh" xcm statemine assets pallet_xcm_benchmarks::generic * Fix * ".git/.scripts/bench-bot.sh" xcm westmint assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" xcm statemint assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" pallet collectives-polkadot collectives pallet_xcm * Fix for collectives * ".git/.scripts/bench-bot.sh" pallet bridge-hub-kusama bridge-hubs pallet_xcm * ".git/.scripts/bench-bot.sh" pallet bridge-hub-rococo bridge-hubs pallet_xcm * Fixes for bridge-hubs * Fixes - return back Weightless * Fix - removed MigrateToTrackInactive for contracts-rococo Co-authored-by: command-bot <> * cargo fmt * Fix benchmarks * Bko gav xcm v3 (#1993) * Fix * ".git/.scripts/bench-bot.sh" xcm statemint assets pallet_xcm_benchmarks::fungible * ".git/.scripts/bench-bot.sh" xcm statemine assets pallet_xcm_benchmarks::fungible * ".git/.scripts/bench-bot.sh" xcm westmint assets pallet_xcm_benchmarks::fungible * ".git/.scripts/bench-bot.sh" xcm statemine assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" xcm statemint assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" xcm westmint assets pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" pallet statemine assets pallet_xcm * ".git/.scripts/bench-bot.sh" pallet westmint assets pallet_xcm * ".git/.scripts/bench-bot.sh" pallet statemint assets pallet_xcm * ".git/.scripts/bench-bot.sh" pallet collectives-polkadot collectives pallet_xcm * ".git/.scripts/bench-bot.sh" pallet bridge-hub-kusama bridge-hubs pallet_xcm * ".git/.scripts/bench-bot.sh" pallet bridge-hub-rococo bridge-hubs pallet_xcm Co-authored-by: command-bot <> * Change AllowUnpaidExecutionFrom to be explicit * xcm-v3 benchmarks, weights, fixes for bridge-hubs (#2035) * Dumy weights to get compile * Change UniversalLocation according to https://github.com/paritytech/polkadot/pull/4097 (Location Inversion Removed) * Fix bridge-hubs weights * ".git/.scripts/bench-bot.sh" pallet statemine assets pallet_xcm * ".git/.scripts/bench-bot.sh" pallet statemint assets pallet_xcm * ".git/.scripts/bench-bot.sh" pallet collectives-polkadot collectives pallet_xcm * ".git/.scripts/bench-bot.sh" pallet westmint assets pallet_xcm * ".git/.scripts/bench-bot.sh" xcm bridge-hub-kusama bridge-hubs pallet_xcm_benchmarks::generic * ".git/.scripts/bench-bot.sh" xcm bridge-hub-kusama bridge-hubs pallet_xcm_benchmarks::fungible * ".git/.scripts/bench-bot.sh" pallet bridge-hub-kusama bridge-hubs pallet_xcm * ".git/.scripts/bench-bot.sh" pallet bridge-hub-rococo bridge-hubs pallet_xcm * ".git/.scripts/bench-bot.sh" xcm bridge-hub-rococo bridge-hubs pallet_xcm_benchmarks::fungible * ".git/.scripts/bench-bot.sh" xcm bridge-hub-rococo bridge-hubs pallet_xcm_benchmarks::generic * Change NetworkId to Option<NetworkId> Co-authored-by: command-bot <> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Add event for showing the hash of an UMP sent message (#1228) * Add UpwardMessageSent event in parachain-system * additional fixes * Message Id * Fix errors from merge * fmt * more fmt * Remove todo * more formatting * Fixes * Fixes * Fixes * Fixes * Allow explicit unpaid executions from the relay chains for system parachains (#2060) * Allow explicit unpaid executions from the relay chains for system parachains * Put origin-filtering barriers into WithComputedOrigin * Use ConstU32<8> * Small nits * formatting * cargo fmt * Allow receiving XCMs from any relay chain plurality * Fixes * update lockfile for {"polkadot", "substrate"} * Update polkadot * Add runtime-benchmarks feature Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: girazoki <gorka.irazoki@gmail.com> Co-authored-by: parity-processbot <>
This commit is contained in:
+167
-92
@@ -33,13 +33,16 @@ pub use pallet::*;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::{convert::TryFrom, prelude::*};
|
||||
use xcm::{
|
||||
latest::{prelude::*, Weight as XcmWeight},
|
||||
VersionedXcm, MAX_XCM_DECODE_DEPTH,
|
||||
};
|
||||
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
|
||||
|
||||
const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB
|
||||
|
||||
// Maximum amount of messages to process per block. This is a temporary measure until we properly
|
||||
// account for proof size weights.
|
||||
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;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
|
||||
pub struct ConfigData {
|
||||
/// The maximum amount of weight any individual message may consume. Messages above this weight
|
||||
@@ -119,8 +122,13 @@ pub mod pallet {
|
||||
|
||||
/// The overweight messages.
|
||||
#[pallet::storage]
|
||||
pub(super) type Overweight<T> =
|
||||
StorageMap<_, Blake2_128Concat, OverweightIndex, (RelayBlockNumber, Vec<u8>), OptionQuery>;
|
||||
pub(super) type Overweight<T> = CountedStorageMap<
|
||||
_,
|
||||
Blake2_128Concat,
|
||||
OverweightIndex,
|
||||
(RelayBlockNumber, Vec<u8>),
|
||||
OptionQuery,
|
||||
>;
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
@@ -145,30 +153,18 @@ pub mod pallet {
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Service a single overweight message.
|
||||
///
|
||||
/// - `origin`: Must pass `ExecuteOverweightOrigin`.
|
||||
/// - `index`: The index of the overweight message to service.
|
||||
/// - `weight_limit`: The amount of weight that message execution may take.
|
||||
///
|
||||
/// Errors:
|
||||
/// - `Unknown`: Message of `index` is unknown.
|
||||
/// - `OverLimit`: Message execution may use greater than `weight_limit`.
|
||||
///
|
||||
/// Events:
|
||||
/// - `OverweightServiced`: On success.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(Weight::from_ref_time(weight_limit.saturating_add(1_000_000)))]
|
||||
#[pallet::weight(weight_limit.saturating_add(Weight::from_ref_time(1_000_000)))]
|
||||
pub fn service_overweight(
|
||||
origin: OriginFor<T>,
|
||||
index: OverweightIndex,
|
||||
weight_limit: XcmWeight,
|
||||
weight_limit: Weight,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
T::ExecuteOverweightOrigin::ensure_origin(origin)?;
|
||||
|
||||
let (sent_at, data) = Overweight::<T>::get(index).ok_or(Error::<T>::Unknown)?;
|
||||
let weight_used =
|
||||
Self::try_service_message(Weight::from_ref_time(weight_limit), sent_at, &data[..])
|
||||
.map_err(|_| Error::<T>::OverLimit)?;
|
||||
let weight_used = Self::try_service_message(weight_limit, sent_at, &data[..])
|
||||
.map_err(|_| Error::<T>::OverLimit)?;
|
||||
Overweight::<T>::remove(index);
|
||||
Self::deposit_event(Event::OverweightServiced { overweight_index: index, weight_used });
|
||||
Ok(Some(weight_used.saturating_add(Weight::from_ref_time(1_000_000))).into())
|
||||
@@ -201,16 +197,29 @@ pub mod pallet {
|
||||
///
|
||||
/// Returns the weight consumed by executing messages in the queue.
|
||||
fn service_queue(limit: Weight) -> Weight {
|
||||
PageIndex::<T>::mutate(|page_index| Self::do_service_queue(limit, page_index))
|
||||
let mut messages_processed = 0;
|
||||
PageIndex::<T>::mutate(|page_index| {
|
||||
Self::do_service_queue(limit, page_index, &mut messages_processed)
|
||||
})
|
||||
}
|
||||
|
||||
/// Exactly equivalent to `service_queue` but expects a mutable `page_index` to be passed
|
||||
/// in and any changes stored.
|
||||
fn do_service_queue(limit: Weight, page_index: &mut PageIndexData) -> Weight {
|
||||
fn do_service_queue(
|
||||
limit: Weight,
|
||||
page_index: &mut PageIndexData,
|
||||
messages_processed: &mut u8,
|
||||
) -> Weight {
|
||||
let mut used = Weight::zero();
|
||||
while page_index.begin_used < page_index.end_used {
|
||||
let page = Pages::<T>::take(page_index.begin_used);
|
||||
for (i, &(sent_at, ref data)) in page.iter().enumerate() {
|
||||
if *messages_processed >= MAX_MESSAGES_PER_BLOCK {
|
||||
// Exceeded block message limit - put the remaining messages back and bail
|
||||
Pages::<T>::insert(page_index.begin_used, &page[i..]);
|
||||
return used
|
||||
}
|
||||
*messages_processed += 1;
|
||||
match Self::try_service_message(limit.saturating_sub(used), sent_at, &data[..])
|
||||
{
|
||||
Ok(w) => used += w,
|
||||
@@ -257,12 +266,12 @@ pub mod pallet {
|
||||
Ok(Weight::zero())
|
||||
},
|
||||
Ok(Ok(x)) => {
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x, limit.ref_time());
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x, message_id, limit);
|
||||
match outcome {
|
||||
Outcome::Error(XcmError::WeightLimitReached(required)) =>
|
||||
Err((message_id, Weight::from_ref_time(required))),
|
||||
Err((message_id, required)),
|
||||
outcome => {
|
||||
let weight_used = Weight::from_ref_time(outcome.weight_used());
|
||||
let weight_used = outcome.weight_used();
|
||||
Self::deposit_event(Event::ExecutedDownward { message_id, outcome });
|
||||
Ok(weight_used)
|
||||
},
|
||||
@@ -280,11 +289,12 @@ pub mod pallet {
|
||||
iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
|
||||
limit: Weight,
|
||||
) -> Weight {
|
||||
let mut messages_processed = 0;
|
||||
let mut page_index = PageIndex::<T>::get();
|
||||
let config = Configuration::<T>::get();
|
||||
|
||||
// First try to use `max_weight` to service the current queue.
|
||||
let mut used = Self::do_service_queue(limit, &mut page_index);
|
||||
let mut used = Self::do_service_queue(limit, &mut page_index, &mut messages_processed);
|
||||
|
||||
// Then if the queue is empty, use the weight remaining to service the incoming messages
|
||||
// and once we run out of weight, place them in the queue.
|
||||
@@ -297,15 +307,21 @@ pub mod pallet {
|
||||
};
|
||||
|
||||
for (i, (sent_at, data)) in iter.enumerate() {
|
||||
if messages_processed >= MAX_MESSAGES_PER_BLOCK {
|
||||
break
|
||||
}
|
||||
if maybe_enqueue_page.is_none() {
|
||||
// We're not currently enqueuing - try to execute inline.
|
||||
let remaining_weight = limit.saturating_sub(used);
|
||||
messages_processed += 1;
|
||||
match Self::try_service_message(remaining_weight, sent_at, &data[..]) {
|
||||
Ok(consumed) => used += consumed,
|
||||
Err((message_id, required_weight)) =>
|
||||
// Too much weight required right now.
|
||||
{
|
||||
if required_weight.any_gt(config.max_individual) {
|
||||
let is_under_limit = Overweight::<T>::count() < MAX_OVERWEIGHT_MESSAGES;
|
||||
used.saturating_accrue(T::DbWeight::get().reads(1));
|
||||
if required_weight.any_gt(config.max_individual) && is_under_limit {
|
||||
// overweight - add to overweight queue and continue with
|
||||
// message execution.
|
||||
let overweight_index = page_index.overweight_count;
|
||||
@@ -367,7 +383,7 @@ mod tests {
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
use std::cell::RefCell;
|
||||
use xcm::latest::{MultiLocation, OriginKind, Weight as XCMWeight};
|
||||
use xcm::latest::{MultiLocation, OriginKind};
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
@@ -442,28 +458,58 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
pub enum Weightless {}
|
||||
impl PreparedMessage for Weightless {
|
||||
fn weight_of(&self) -> Weight {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MockExec;
|
||||
impl ExecuteXcm<RuntimeCall> for MockExec {
|
||||
type Prepared = Weightless;
|
||||
|
||||
fn prepare(_message: Xcm) -> Result<Self::Prepared, Xcm> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn execute(
|
||||
_origin: impl Into<MultiLocation>,
|
||||
_pre: Weightless,
|
||||
_hash: XcmHash,
|
||||
_weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn execute_xcm_in_credit(
|
||||
_origin: impl Into<MultiLocation>,
|
||||
message: Xcm,
|
||||
weight_limit: XCMWeight,
|
||||
_credit: XCMWeight,
|
||||
_hash: XcmHash,
|
||||
weight_limit: Weight,
|
||||
_weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
let o = match (message.0.len(), &message.0.first()) {
|
||||
(1, Some(Transact { require_weight_at_most, .. })) => {
|
||||
if *require_weight_at_most <= weight_limit {
|
||||
if require_weight_at_most.all_lte(weight_limit) {
|
||||
Outcome::Complete(*require_weight_at_most)
|
||||
} else {
|
||||
Outcome::Error(XcmError::WeightLimitReached(*require_weight_at_most))
|
||||
}
|
||||
},
|
||||
// use 1000 to decide that it's not supported.
|
||||
_ => Outcome::Incomplete(1000.min(weight_limit), XcmError::Unimplemented),
|
||||
_ => Outcome::Incomplete(
|
||||
Weight::from_parts(1000, 1000).min(weight_limit),
|
||||
XcmError::Unimplemented,
|
||||
),
|
||||
};
|
||||
TRACE.with(|q| q.borrow_mut().push((message, o.clone())));
|
||||
o
|
||||
}
|
||||
|
||||
fn charge_fees(_location: impl Into<MultiLocation>, _fees: MultiAssets) -> XcmResult {
|
||||
Err(XcmError::Unimplemented)
|
||||
}
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
@@ -498,20 +544,23 @@ mod tests {
|
||||
DmpQueue::handle_dmp_messages(iter, limit)
|
||||
}
|
||||
|
||||
fn msg(weight: XCMWeight) -> Xcm {
|
||||
fn msg(weight: u64) -> Xcm {
|
||||
Xcm(vec![Transact {
|
||||
origin_type: OriginKind::Native,
|
||||
require_weight_at_most: weight,
|
||||
origin_kind: OriginKind::Native,
|
||||
require_weight_at_most: Weight::from_parts(weight, weight),
|
||||
call: Vec::new().into(),
|
||||
}])
|
||||
}
|
||||
|
||||
fn msg_complete(weight: XCMWeight) -> (Xcm, Outcome) {
|
||||
(msg(weight), Outcome::Complete(weight))
|
||||
fn msg_complete(weight: u64) -> (Xcm, Outcome) {
|
||||
(msg(weight), Outcome::Complete(Weight::from_parts(weight, weight)))
|
||||
}
|
||||
|
||||
fn msg_limit_reached(weight: XCMWeight) -> (Xcm, Outcome) {
|
||||
(msg(weight), Outcome::Error(XcmError::WeightLimitReached(weight)))
|
||||
fn msg_limit_reached(weight: u64) -> (Xcm, Outcome) {
|
||||
(
|
||||
msg(weight),
|
||||
Outcome::Error(XcmError::WeightLimitReached(Weight::from_parts(weight, weight))),
|
||||
)
|
||||
}
|
||||
|
||||
fn pages_queued() -> PageCounter {
|
||||
@@ -531,7 +580,7 @@ mod tests {
|
||||
#[test]
|
||||
fn basic_setup_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(1000));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(1000, 1000));
|
||||
assert_eq!(weight_used, Weight::zero());
|
||||
assert_eq!(take_trace(), Vec::new());
|
||||
assert!(queue_is_empty());
|
||||
@@ -542,8 +591,8 @@ mod tests {
|
||||
fn service_inline_complete_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let incoming = vec![msg(1000), msg(1001)];
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(2500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(2001));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::from_parts(2001, 2001));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001)]);
|
||||
assert!(queue_is_empty());
|
||||
});
|
||||
@@ -554,8 +603,8 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let enqueued = vec![msg(1000), msg(1001), msg(1002)];
|
||||
enqueue(&enqueued);
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(2500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(2001));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::from_parts(2001, 2001));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![msg_complete(1000), msg_complete(1001), msg_limit_reached(1002),]
|
||||
@@ -567,7 +616,7 @@ mod tests {
|
||||
fn enqueue_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let incoming = vec![msg(1000), msg(1001), msg(1002)];
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(999));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(999, 999));
|
||||
assert_eq!(weight_used, Weight::zero());
|
||||
assert_eq!(
|
||||
PageIndex::<Test>::get(),
|
||||
@@ -576,15 +625,15 @@ mod tests {
|
||||
assert_eq!(Pages::<Test>::get(0).len(), 3);
|
||||
assert_eq!(take_trace(), vec![msg_limit_reached(1000)]);
|
||||
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(2500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(2001));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::from_parts(2001, 2001));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![msg_complete(1000), msg_complete(1001), msg_limit_reached(1002),]
|
||||
);
|
||||
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(2500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(1002));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::from_parts(1002, 1002));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1002),]);
|
||||
assert!(queue_is_empty());
|
||||
});
|
||||
@@ -594,14 +643,14 @@ mod tests {
|
||||
fn service_inline_then_enqueue_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let incoming = vec![msg(1000), msg(1001), msg(1002)];
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(1500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(1000));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(1500, 1500));
|
||||
assert_eq!(weight_used, Weight::from_parts(1000, 1000));
|
||||
assert_eq!(pages_queued(), 1);
|
||||
assert_eq!(Pages::<Test>::get(0).len(), 2);
|
||||
assert_eq!(take_trace(), vec![msg_complete(1000), msg_limit_reached(1001),]);
|
||||
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(2500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(2003));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::from_parts(2003, 2003));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1001), msg_complete(1002),]);
|
||||
assert!(queue_is_empty());
|
||||
});
|
||||
@@ -613,8 +662,8 @@ mod tests {
|
||||
let enqueued = vec![msg(1000), msg(1001)];
|
||||
let incoming = vec![msg(1002), msg(1003)];
|
||||
enqueue(&enqueued);
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(5000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(4006));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000));
|
||||
assert_eq!(weight_used, Weight::from_parts(4006, 4006));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![
|
||||
@@ -634,19 +683,19 @@ mod tests {
|
||||
let enqueued = vec![msg(1000), msg(10001)];
|
||||
let incoming = vec![msg(1002), msg(1003)];
|
||||
enqueue(&enqueued);
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(5000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(1000));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000));
|
||||
assert_eq!(weight_used, Weight::from_parts(1000, 1000));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1000), msg_limit_reached(10001),]);
|
||||
assert_eq!(pages_queued(), 2);
|
||||
|
||||
// 5000 is not enough to process the 10001 blocker, so nothing happens.
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(5000));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(5000, 5000));
|
||||
assert_eq!(weight_used, Weight::zero());
|
||||
assert_eq!(take_trace(), vec![msg_limit_reached(10001),]);
|
||||
|
||||
// 20000 is now enough to process everything.
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(20000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(12006));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000));
|
||||
assert_eq!(weight_used, Weight::from_parts(12006, 12006));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![msg_complete(10001), msg_complete(1002), msg_complete(1003),]
|
||||
@@ -661,8 +710,8 @@ mod tests {
|
||||
let enqueued = vec![msg(1000), msg(1001)];
|
||||
let incoming = vec![msg(10002), msg(1003)];
|
||||
enqueue(&enqueued);
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(5000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(2001));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000));
|
||||
assert_eq!(weight_used, Weight::from_parts(2001, 2001));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![msg_complete(1000), msg_complete(1001), msg_limit_reached(10002),]
|
||||
@@ -670,8 +719,8 @@ mod tests {
|
||||
assert_eq!(pages_queued(), 1);
|
||||
|
||||
// 20000 is now enough to process everything.
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(20000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(11005));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000));
|
||||
assert_eq!(weight_used, Weight::from_parts(11005, 11005));
|
||||
assert_eq!(take_trace(), vec![msg_complete(10002), msg_complete(1003),]);
|
||||
assert!(queue_is_empty());
|
||||
});
|
||||
@@ -683,8 +732,8 @@ mod tests {
|
||||
let enqueued = vec![msg(1000), msg(1001)];
|
||||
let incoming = vec![msg(1002), msg(10003)];
|
||||
enqueue(&enqueued);
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(5000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(3003));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(5000, 5000));
|
||||
assert_eq!(weight_used, Weight::from_parts(3003, 3003));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![
|
||||
@@ -697,8 +746,8 @@ mod tests {
|
||||
assert_eq!(pages_queued(), 1);
|
||||
|
||||
// 20000 is now enough to process everything.
|
||||
let weight_used = handle_messages(&[], Weight::from_ref_time(20000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(10003));
|
||||
let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000));
|
||||
assert_eq!(weight_used, Weight::from_parts(10003, 10003));
|
||||
assert_eq!(take_trace(), vec![msg_complete(10003),]);
|
||||
assert!(queue_is_empty());
|
||||
});
|
||||
@@ -709,20 +758,20 @@ mod tests {
|
||||
new_test_ext().execute_with(|| {
|
||||
let enqueued = vec![msg(1000), msg(1001)];
|
||||
enqueue(&enqueued);
|
||||
let weight_used = handle_messages(&vec![msg(1002)], Weight::from_ref_time(1500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(1000));
|
||||
let weight_used = handle_messages(&vec![msg(1002)], Weight::from_parts(1500, 1500));
|
||||
assert_eq!(weight_used, Weight::from_parts(1000, 1000));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1000), msg_limit_reached(1001),]);
|
||||
assert_eq!(pages_queued(), 2);
|
||||
assert_eq!(PageIndex::<Test>::get().begin_used, 0);
|
||||
|
||||
let weight_used = handle_messages(&vec![msg(1003)], Weight::from_ref_time(1500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(1001));
|
||||
let weight_used = handle_messages(&vec![msg(1003)], Weight::from_parts(1500, 1500));
|
||||
assert_eq!(weight_used, Weight::from_parts(1001, 1001));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1001), msg_limit_reached(1002),]);
|
||||
assert_eq!(pages_queued(), 2);
|
||||
assert_eq!(PageIndex::<Test>::get().begin_used, 1);
|
||||
|
||||
let weight_used = handle_messages(&vec![msg(1004)], Weight::from_ref_time(1500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(1002));
|
||||
let weight_used = handle_messages(&vec![msg(1004)], Weight::from_parts(1500, 1500));
|
||||
assert_eq!(weight_used, Weight::from_parts(1002, 1002));
|
||||
assert_eq!(take_trace(), vec![msg_complete(1002), msg_limit_reached(1003),]);
|
||||
assert_eq!(pages_queued(), 2);
|
||||
assert_eq!(PageIndex::<Test>::get().begin_used, 2);
|
||||
@@ -733,11 +782,13 @@ mod tests {
|
||||
fn overweight_should_not_block_queue() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set the overweight threshold to 9999.
|
||||
Configuration::<Test>::put(ConfigData { max_individual: Weight::from_ref_time(9999) });
|
||||
Configuration::<Test>::put(ConfigData {
|
||||
max_individual: Weight::from_parts(9999, 9999),
|
||||
});
|
||||
|
||||
let incoming = vec![msg(1000), msg(10001), msg(1002)];
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(2500));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(2002));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::from_parts(2002, 2002));
|
||||
assert!(queue_is_empty());
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
@@ -752,40 +803,64 @@ mod tests {
|
||||
fn overweights_should_be_manually_executable() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set the overweight threshold to 9999.
|
||||
Configuration::<Test>::put(ConfigData { max_individual: Weight::from_ref_time(9999) });
|
||||
Configuration::<Test>::put(ConfigData {
|
||||
max_individual: Weight::from_parts(9999, 9999),
|
||||
});
|
||||
|
||||
let incoming = vec![msg(10000)];
|
||||
let weight_used = handle_messages(&incoming, Weight::from_ref_time(2500));
|
||||
let weight_used = handle_messages(&incoming, Weight::from_parts(2500, 2500));
|
||||
assert_eq!(weight_used, Weight::zero());
|
||||
assert_eq!(take_trace(), vec![msg_limit_reached(10000)]);
|
||||
assert_eq!(overweights(), vec![0]);
|
||||
|
||||
assert_noop!(
|
||||
DmpQueue::service_overweight(RuntimeOrigin::signed(1), 0, 20000),
|
||||
DmpQueue::service_overweight(
|
||||
RuntimeOrigin::signed(1),
|
||||
0,
|
||||
Weight::from_parts(20000, 20000)
|
||||
),
|
||||
BadOrigin
|
||||
);
|
||||
assert_noop!(
|
||||
DmpQueue::service_overweight(RuntimeOrigin::root(), 1, 20000),
|
||||
DmpQueue::service_overweight(
|
||||
RuntimeOrigin::root(),
|
||||
1,
|
||||
Weight::from_parts(20000, 20000)
|
||||
),
|
||||
Error::<Test>::Unknown
|
||||
);
|
||||
assert_noop!(
|
||||
DmpQueue::service_overweight(RuntimeOrigin::root(), 0, 9999),
|
||||
DmpQueue::service_overweight(
|
||||
RuntimeOrigin::root(),
|
||||
0,
|
||||
Weight::from_parts(9999, 9999)
|
||||
),
|
||||
Error::<Test>::OverLimit
|
||||
);
|
||||
assert_eq!(take_trace(), vec![msg_limit_reached(10000)]);
|
||||
|
||||
let base_weight = super::Call::<Test>::service_overweight { index: 0, weight_limit: 0 }
|
||||
.get_dispatch_info()
|
||||
.weight;
|
||||
let base_weight =
|
||||
super::Call::<Test>::service_overweight { index: 0, weight_limit: Weight::zero() }
|
||||
.get_dispatch_info()
|
||||
.weight;
|
||||
use frame_support::dispatch::GetDispatchInfo;
|
||||
let info = DmpQueue::service_overweight(RuntimeOrigin::root(), 0, 20000).unwrap();
|
||||
let info = DmpQueue::service_overweight(
|
||||
RuntimeOrigin::root(),
|
||||
0,
|
||||
Weight::from_parts(20000, 20000),
|
||||
)
|
||||
.unwrap();
|
||||
let actual_weight = info.actual_weight.unwrap();
|
||||
assert_eq!(actual_weight, base_weight + Weight::from_ref_time(10000));
|
||||
assert_eq!(actual_weight, base_weight + Weight::from_parts(10000, 10000));
|
||||
assert_eq!(take_trace(), vec![msg_complete(10000)]);
|
||||
assert!(overweights().is_empty());
|
||||
|
||||
assert_noop!(
|
||||
DmpQueue::service_overweight(RuntimeOrigin::root(), 0, 20000),
|
||||
DmpQueue::service_overweight(
|
||||
RuntimeOrigin::root(),
|
||||
0,
|
||||
Weight::from_parts(20000, 20000)
|
||||
),
|
||||
Error::<Test>::Unknown
|
||||
);
|
||||
});
|
||||
@@ -798,8 +873,8 @@ mod tests {
|
||||
enqueue(&vec![msg(1002), msg(1003)]);
|
||||
enqueue(&vec![msg(1004), msg(1005)]);
|
||||
|
||||
let weight_used = DmpQueue::on_idle(1, Weight::from_ref_time(6000));
|
||||
assert_eq!(weight_used, Weight::from_ref_time(5010));
|
||||
let weight_used = DmpQueue::on_idle(1, Weight::from_parts(6000, 6000));
|
||||
assert_eq!(weight_used, Weight::from_parts(5010, 5010));
|
||||
assert_eq!(
|
||||
take_trace(),
|
||||
vec![
|
||||
|
||||
@@ -22,7 +22,6 @@ use frame_support::{
|
||||
traits::StorageVersion,
|
||||
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight},
|
||||
};
|
||||
use xcm::latest::Weight as XcmWeight;
|
||||
|
||||
/// The current storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
@@ -33,8 +32,15 @@ pub fn migrate_to_latest<T: Config>() -> Weight {
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
|
||||
if StorageVersion::get::<Pallet<T>>() == 0 {
|
||||
weight += migrate_to_v1::<T>();
|
||||
weight.saturating_accrue(migrate_to_v1::<T>());
|
||||
StorageVersion::new(1).put::<Pallet<T>>();
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
}
|
||||
|
||||
if StorageVersion::get::<Pallet<T>>() == 1 {
|
||||
weight.saturating_accrue(migrate_to_v2::<T>());
|
||||
StorageVersion::new(2).put::<Pallet<T>>();
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
}
|
||||
|
||||
weight
|
||||
@@ -46,7 +52,7 @@ mod v0 {
|
||||
|
||||
#[derive(Decode, Encode, Debug)]
|
||||
pub struct ConfigData {
|
||||
pub max_individual: XcmWeight,
|
||||
pub max_individual: u64,
|
||||
}
|
||||
|
||||
impl Default for ConfigData {
|
||||
@@ -78,6 +84,16 @@ pub fn migrate_to_v1<T: Config>() -> Weight {
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
}
|
||||
|
||||
/// Migrates `Overweight` so that it initializes the storage map's counter.
|
||||
///
|
||||
/// NOTE: Only use this function if you know what you're doing. Default to using
|
||||
/// `migrate_to_latest`.
|
||||
pub fn migrate_to_v2<T: Config>() -> Weight {
|
||||
let overweight_messages = <Pallet<T> as Store>::Overweight::initialize_counter() as u64;
|
||||
|
||||
T::DbWeight::get().reads_writes(overweight_messages, 1)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -28,6 +28,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
|
||||
|
||||
# Polkadot
|
||||
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, features = [ "wasm-api" ], branch = "master" }
|
||||
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||
|
||||
# Cumulus
|
||||
cumulus-pallet-parachain-system-proc-macro = { path = "proc-macro", default-features = false }
|
||||
@@ -67,6 +68,7 @@ std = [
|
||||
"sp-state-machine/std",
|
||||
"sp-std/std",
|
||||
"sp-trie/std",
|
||||
"xcm/std",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
|
||||
@@ -53,6 +53,7 @@ use sp_runtime::{
|
||||
},
|
||||
};
|
||||
use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
|
||||
use xcm::latest::XcmHash;
|
||||
|
||||
mod migration;
|
||||
mod relay_state_snapshot;
|
||||
@@ -480,6 +481,8 @@ pub mod pallet {
|
||||
DownwardMessagesReceived { count: u32 },
|
||||
/// Downward messages were processed using the given weight.
|
||||
DownwardMessagesProcessed { weight_used: Weight, dmq_head: relay_chain::Hash },
|
||||
/// An upward message was sent to the relay chain.
|
||||
UpwardMessageSent { message_hash: Option<XcmHash> },
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
@@ -743,7 +746,7 @@ impl<T: Config> GetChannelInfo for Pallet<T> {
|
||||
// None then it must be that this is an edge-case where a message is attempted to be
|
||||
// sent at the first block. It should be safe to assume that there are no channels
|
||||
// opened at all so early. At least, relying on this assumption seems to be a better
|
||||
// tradeoff, compared to introducing an error variant that the clients should be
|
||||
// trade-off, compared to introducing an error variant that the clients should be
|
||||
// prepared to handle.
|
||||
let index = match channels.binary_search_by_key(&id, |item| item.0) {
|
||||
Err(_) => return ChannelStatus::Closed,
|
||||
@@ -1004,7 +1007,7 @@ impl<T: Config> frame_system::SetCode<T> for ParachainSetCode<T> {
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn send_upward_message(message: UpwardMessage) -> Result<u32, MessageSendError> {
|
||||
pub fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
|
||||
// Check if the message fits into the relay-chain constraints.
|
||||
//
|
||||
// Note, that we are using `host_configuration` here which may be from the previous
|
||||
@@ -1034,13 +1037,18 @@ impl<T: Config> Pallet<T> {
|
||||
// Thus fall through here.
|
||||
},
|
||||
};
|
||||
<PendingUpwardMessages<T>>::append(message);
|
||||
Ok(0)
|
||||
<PendingUpwardMessages<T>>::append(message.clone());
|
||||
|
||||
// The relay ump does not use using_encoded
|
||||
// We apply the same this to use the same hash
|
||||
let hash = sp_io::hashing::blake2_256(&message);
|
||||
Self::deposit_event(Event::UpwardMessageSent { message_hash: Some(hash) });
|
||||
Ok((0, hash))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> UpwardMessageSender for Pallet<T> {
|
||||
fn send_upward_message(message: UpwardMessage) -> Result<u32, MessageSendError> {
|
||||
fn send_upward_message(message: UpwardMessage) -> Result<(u32, XcmHash), MessageSendError> {
|
||||
Self::send_upward_message(message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,13 +67,13 @@ pub mod pallet {
|
||||
pub enum Event<T: Config> {
|
||||
/// Downward message is invalid XCM.
|
||||
/// \[ id \]
|
||||
InvalidFormat([u8; 8]),
|
||||
InvalidFormat([u8; 32]),
|
||||
/// Downward message is unsupported version of XCM.
|
||||
/// \[ id \]
|
||||
UnsupportedVersion([u8; 8]),
|
||||
UnsupportedVersion([u8; 32]),
|
||||
/// Downward message executed with the given outcome.
|
||||
/// \[ id, outcome \]
|
||||
ExecutedDownward([u8; 8], Outcome),
|
||||
ExecutedDownward([u8; 32], Outcome),
|
||||
}
|
||||
|
||||
/// Origin for the parachains module.
|
||||
@@ -113,7 +113,7 @@ impl<T: Config> DmpMessageHandler for UnlimitedDmpExecution<T> {
|
||||
) -> Weight {
|
||||
let mut used = Weight::zero();
|
||||
for (_sent_at, data) in iter {
|
||||
let id = sp_io::hashing::twox_64(&data[..]);
|
||||
let id = sp_io::hashing::blake2_256(&data[..]);
|
||||
let msg = VersionedXcm::<T::RuntimeCall>::decode_all_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut data.as_slice(),
|
||||
@@ -123,8 +123,8 @@ impl<T: Config> DmpMessageHandler for UnlimitedDmpExecution<T> {
|
||||
Err(_) => Pallet::<T>::deposit_event(Event::InvalidFormat(id)),
|
||||
Ok(Err(())) => Pallet::<T>::deposit_event(Event::UnsupportedVersion(id)),
|
||||
Ok(Ok(x)) => {
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x, limit.ref_time());
|
||||
used += Weight::from_ref_time(outcome.weight_used());
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x, id, limit);
|
||||
used = used.saturating_add(outcome.weight_used());
|
||||
Pallet::<T>::deposit_event(Event::ExecutedDownward(id, outcome));
|
||||
},
|
||||
}
|
||||
@@ -146,7 +146,7 @@ impl<T: Config> DmpMessageHandler for LimitAndDropDmpExecution<T> {
|
||||
) -> Weight {
|
||||
let mut used = Weight::zero();
|
||||
for (_sent_at, data) in iter {
|
||||
let id = sp_io::hashing::twox_64(&data[..]);
|
||||
let id = sp_io::hashing::blake2_256(&data[..]);
|
||||
let msg = VersionedXcm::<T::RuntimeCall>::decode_all_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut data.as_slice(),
|
||||
@@ -157,8 +157,8 @@ impl<T: Config> DmpMessageHandler for LimitAndDropDmpExecution<T> {
|
||||
Ok(Err(())) => Pallet::<T>::deposit_event(Event::UnsupportedVersion(id)),
|
||||
Ok(Ok(x)) => {
|
||||
let weight_limit = limit.saturating_sub(used);
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x, weight_limit.ref_time());
|
||||
used += Weight::from_ref_time(outcome.weight_used());
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x, id, weight_limit);
|
||||
used = used.saturating_add(outcome.weight_used());
|
||||
Pallet::<T>::deposit_event(Event::ExecutedDownward(id, outcome));
|
||||
},
|
||||
}
|
||||
|
||||
@@ -13,10 +13,12 @@ scale-info = { version = "2.3.1", default-features = false, features = ["derive"
|
||||
# Substrate
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
# Polkadot
|
||||
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
|
||||
|
||||
@@ -30,7 +32,6 @@ frame-benchmarking = { default-features = false, optional = true, git = "https:/
|
||||
|
||||
# Substrate
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
# Polkadot
|
||||
@@ -48,6 +49,8 @@ std = [
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"log/std",
|
||||
"polkadot-runtime-common/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
"xcm-executor/std",
|
||||
|
||||
@@ -22,7 +22,7 @@ use frame_system::RawOrigin;
|
||||
|
||||
benchmarks! {
|
||||
set_config_with_u32 {}: update_resume_threshold(RawOrigin::Root, 100)
|
||||
set_config_with_weight {}: update_weight_restrict_decay(RawOrigin::Root, 3_000_000)
|
||||
set_config_with_weight {}: update_weight_restrict_decay(RawOrigin::Root, Weight::from_ref_time(3_000_000))
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
|
||||
+117
-84
@@ -44,20 +44,18 @@ use cumulus_primitives_core::{
|
||||
ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource,
|
||||
};
|
||||
use frame_support::{
|
||||
traits::EnsureOrigin,
|
||||
traits::{EnsureOrigin, Get},
|
||||
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight},
|
||||
};
|
||||
use polkadot_runtime_common::xcm_sender::ConstantPrice;
|
||||
use rand_chacha::{
|
||||
rand_core::{RngCore, SeedableRng},
|
||||
ChaChaRng,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{traits::Hash, RuntimeDebug};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::{convert::TryFrom, prelude::*};
|
||||
use xcm::{
|
||||
latest::{prelude::*, Weight as XcmWeight},
|
||||
VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH,
|
||||
};
|
||||
use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH};
|
||||
use xcm_executor::traits::ConvertOrigin;
|
||||
|
||||
pub use pallet::*;
|
||||
@@ -68,6 +66,12 @@ pub type OverweightIndex = u64;
|
||||
const LOG_TARGET: &str = "xcmp_queue";
|
||||
const DEFAULT_POV_SIZE: u64 = 64 * 1024; // 64 KB
|
||||
|
||||
// Maximum amount of messages to process per block. This is a temporary measure until we properly
|
||||
// account for proof size weights.
|
||||
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;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
@@ -103,6 +107,9 @@ pub mod pallet {
|
||||
/// superuser origin.
|
||||
type ControllerOriginConverter: ConvertOrigin<Self::RuntimeOrigin>;
|
||||
|
||||
/// The price for delivering an XCM to a sibling parachain destination.
|
||||
type PriceForSiblingDelivery: PriceForSiblingDelivery;
|
||||
|
||||
/// The weight information of this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
@@ -135,11 +142,11 @@ pub mod pallet {
|
||||
/// Events:
|
||||
/// - `OverweightServiced`: On success.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight((Weight::from_ref_time(weight_limit.saturating_add(1_000_000)), DispatchClass::Operational,))]
|
||||
#[pallet::weight((weight_limit.saturating_add(Weight::from_ref_time(1_000_000)), DispatchClass::Operational))]
|
||||
pub fn service_overweight(
|
||||
origin: OriginFor<T>,
|
||||
index: OverweightIndex,
|
||||
weight_limit: XcmWeight,
|
||||
weight_limit: Weight,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
T::ExecuteOverweightOrigin::ensure_origin(origin)?;
|
||||
|
||||
@@ -150,9 +157,8 @@ pub mod pallet {
|
||||
&mut data.as_slice(),
|
||||
)
|
||||
.map_err(|_| Error::<T>::BadXcm)?;
|
||||
let used =
|
||||
Self::handle_xcm_message(sender, sent_at, xcm, Weight::from_ref_time(weight_limit))
|
||||
.map_err(|_| Error::<T>::WeightOverLimit)?;
|
||||
let used = Self::handle_xcm_message(sender, sent_at, xcm, weight_limit)
|
||||
.map_err(|_| Error::<T>::WeightOverLimit)?;
|
||||
Overweight::<T>::remove(index);
|
||||
Self::deposit_event(Event::OverweightServiced { index, used });
|
||||
Ok(Some(used.saturating_add(Weight::from_ref_time(1_000_000))).into())
|
||||
@@ -234,9 +240,9 @@ pub mod pallet {
|
||||
/// - `new`: Desired value for `QueueConfigData.threshold_weight`
|
||||
#[pallet::call_index(6)]
|
||||
#[pallet::weight((T::WeightInfo::set_config_with_weight(), DispatchClass::Operational,))]
|
||||
pub fn update_threshold_weight(origin: OriginFor<T>, new: XcmWeight) -> DispatchResult {
|
||||
pub fn update_threshold_weight(origin: OriginFor<T>, new: Weight) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
QueueConfig::<T>::mutate(|data| data.threshold_weight = Weight::from_ref_time(new));
|
||||
QueueConfig::<T>::mutate(|data| data.threshold_weight = new);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -248,14 +254,9 @@ pub mod pallet {
|
||||
/// - `new`: Desired value for `QueueConfigData.weight_restrict_decay`.
|
||||
#[pallet::call_index(7)]
|
||||
#[pallet::weight((T::WeightInfo::set_config_with_weight(), DispatchClass::Operational,))]
|
||||
pub fn update_weight_restrict_decay(
|
||||
origin: OriginFor<T>,
|
||||
new: XcmWeight,
|
||||
) -> DispatchResult {
|
||||
pub fn update_weight_restrict_decay(origin: OriginFor<T>, new: Weight) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
QueueConfig::<T>::mutate(|data| {
|
||||
data.weight_restrict_decay = Weight::from_ref_time(new)
|
||||
});
|
||||
QueueConfig::<T>::mutate(|data| data.weight_restrict_decay = new);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -269,12 +270,10 @@ pub mod pallet {
|
||||
#[pallet::weight((T::WeightInfo::set_config_with_weight(), DispatchClass::Operational,))]
|
||||
pub fn update_xcmp_max_individual_weight(
|
||||
origin: OriginFor<T>,
|
||||
new: XcmWeight,
|
||||
new: Weight,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
QueueConfig::<T>::mutate(|data| {
|
||||
data.xcmp_max_individual_weight = Weight::from_ref_time(new)
|
||||
});
|
||||
QueueConfig::<T>::mutate(|data| data.xcmp_max_individual_weight = new);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -284,17 +283,15 @@ pub mod pallet {
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// Some XCM was executed ok.
|
||||
Success { message_hash: Option<T::Hash>, weight: Weight },
|
||||
Success { message_hash: Option<XcmHash>, weight: Weight },
|
||||
/// Some XCM failed.
|
||||
Fail { message_hash: Option<T::Hash>, error: XcmError, weight: Weight },
|
||||
Fail { message_hash: Option<XcmHash>, error: XcmError, weight: Weight },
|
||||
/// Bad XCM version used.
|
||||
BadVersion { message_hash: Option<T::Hash> },
|
||||
BadVersion { message_hash: Option<XcmHash> },
|
||||
/// Bad XCM format used.
|
||||
BadFormat { message_hash: Option<T::Hash> },
|
||||
/// An upward message was sent to the relay chain.
|
||||
UpwardMessageSent { message_hash: Option<T::Hash> },
|
||||
BadFormat { message_hash: Option<XcmHash> },
|
||||
/// An HRMP message was sent to a sibling parachain.
|
||||
XcmpMessageSent { message_hash: Option<T::Hash> },
|
||||
XcmpMessageSent { message_hash: Option<XcmHash> },
|
||||
/// An XCM exceeded the individual message weight budget.
|
||||
OverweightEnqueued {
|
||||
sender: ParaId,
|
||||
@@ -368,7 +365,7 @@ pub mod pallet {
|
||||
/// `service_overweight`.
|
||||
#[pallet::storage]
|
||||
pub(super) type Overweight<T: Config> =
|
||||
StorageMap<_, Twox64Concat, OverweightIndex, (ParaId, RelayBlockNumber, Vec<u8>)>;
|
||||
CountedStorageMap<_, Twox64Concat, OverweightIndex, (ParaId, RelayBlockNumber, Vec<u8>)>;
|
||||
|
||||
/// The number of overweight messages ever recorded in `Overweight`. Also doubles as the next
|
||||
/// available free overweight index.
|
||||
@@ -623,34 +620,23 @@ impl<T: Config> Pallet<T> {
|
||||
xcm: VersionedXcm<T::RuntimeCall>,
|
||||
max_weight: Weight,
|
||||
) -> Result<Weight, XcmError> {
|
||||
let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
|
||||
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
|
||||
log::debug!("Processing XCMP-XCM: {:?}", &hash);
|
||||
let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
|
||||
Ok(xcm) => {
|
||||
let location = (1, Parachain(sender.into()));
|
||||
let location = (Parent, Parachain(sender.into()));
|
||||
|
||||
match T::XcmExecutor::execute_xcm(location, xcm, max_weight.ref_time()) {
|
||||
match T::XcmExecutor::execute_xcm(location, xcm, hash, max_weight) {
|
||||
Outcome::Error(e) => (
|
||||
Err(e),
|
||||
Event::Fail { message_hash: Some(hash), error: e, weight: Weight::zero() },
|
||||
),
|
||||
Outcome::Complete(w) => (
|
||||
Ok(Weight::from_ref_time(w)),
|
||||
Event::Success {
|
||||
message_hash: Some(hash),
|
||||
weight: Weight::from_ref_time(w),
|
||||
},
|
||||
),
|
||||
Outcome::Complete(w) =>
|
||||
(Ok(w), Event::Success { message_hash: Some(hash), weight: w }),
|
||||
// As far as the caller is concerned, this was dispatched without error, so
|
||||
// we just report the weight used.
|
||||
Outcome::Incomplete(w, e) => (
|
||||
Ok(Weight::from_ref_time(w)),
|
||||
Event::Fail {
|
||||
message_hash: Some(hash),
|
||||
error: e,
|
||||
weight: Weight::from_ref_time(w),
|
||||
},
|
||||
),
|
||||
Outcome::Incomplete(w, e) =>
|
||||
(Ok(w), Event::Fail { message_hash: Some(hash), error: e, weight: w }),
|
||||
}
|
||||
},
|
||||
Err(()) =>
|
||||
@@ -663,6 +649,7 @@ impl<T: Config> Pallet<T> {
|
||||
fn process_xcmp_message(
|
||||
sender: ParaId,
|
||||
(sent_at, format): (RelayBlockNumber, XcmpMessageFormat),
|
||||
messages_processed: &mut u8,
|
||||
max_weight: Weight,
|
||||
max_individual_weight: Weight,
|
||||
) -> (Weight, bool) {
|
||||
@@ -672,35 +659,45 @@ impl<T: Config> Pallet<T> {
|
||||
let mut weight_used = Weight::zero();
|
||||
match format {
|
||||
XcmpMessageFormat::ConcatenatedVersionedXcm => {
|
||||
while !remaining_fragments.is_empty() {
|
||||
while !remaining_fragments.is_empty() &&
|
||||
*messages_processed < MAX_MESSAGES_PER_BLOCK
|
||||
{
|
||||
last_remaining_fragments = remaining_fragments;
|
||||
if let Ok(xcm) = VersionedXcm::<T::RuntimeCall>::decode_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut remaining_fragments,
|
||||
) {
|
||||
let weight = max_weight - weight_used;
|
||||
*messages_processed += 1;
|
||||
match Self::handle_xcm_message(sender, sent_at, xcm, weight) {
|
||||
Ok(used) => weight_used = weight_used.saturating_add(used),
|
||||
Err(XcmError::WeightLimitReached(required))
|
||||
if required > max_individual_weight.ref_time() =>
|
||||
if required.any_gt(max_individual_weight) =>
|
||||
{
|
||||
// overweight - add to overweight queue and continue with message
|
||||
// execution consuming the message.
|
||||
let msg_len = last_remaining_fragments
|
||||
.len()
|
||||
.saturating_sub(remaining_fragments.len());
|
||||
let overweight_xcm = last_remaining_fragments[..msg_len].to_vec();
|
||||
let index = Self::stash_overweight(sender, sent_at, overweight_xcm);
|
||||
let e = Event::OverweightEnqueued {
|
||||
sender,
|
||||
sent_at,
|
||||
index,
|
||||
required: Weight::from_ref_time(required),
|
||||
};
|
||||
Self::deposit_event(e);
|
||||
let is_under_limit =
|
||||
Overweight::<T>::count() < MAX_OVERWEIGHT_MESSAGES;
|
||||
weight_used.saturating_accrue(T::DbWeight::get().reads(1));
|
||||
if is_under_limit {
|
||||
// overweight - add to overweight queue and continue with message
|
||||
// execution consuming the message.
|
||||
let msg_len = last_remaining_fragments
|
||||
.len()
|
||||
.saturating_sub(remaining_fragments.len());
|
||||
let overweight_xcm =
|
||||
last_remaining_fragments[..msg_len].to_vec();
|
||||
let index =
|
||||
Self::stash_overweight(sender, sent_at, overweight_xcm);
|
||||
let e = Event::OverweightEnqueued {
|
||||
sender,
|
||||
sent_at,
|
||||
index,
|
||||
required,
|
||||
};
|
||||
Self::deposit_event(e);
|
||||
}
|
||||
},
|
||||
Err(XcmError::WeightLimitReached(required))
|
||||
if required <= max_weight.ref_time() =>
|
||||
if required.all_lte(max_weight) =>
|
||||
{
|
||||
// That message didn't get processed this time because of being
|
||||
// too heavy. We leave it around for next time and bail.
|
||||
@@ -727,6 +724,7 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
if let Ok(blob) = <Vec<u8>>::decode(&mut remaining_fragments) {
|
||||
let weight = max_weight - weight_used;
|
||||
*messages_processed += 1;
|
||||
match Self::handle_blob_message(sender, sent_at, blob, weight) {
|
||||
Ok(used) => weight_used = weight_used.saturating_add(used),
|
||||
Err(true) => {
|
||||
@@ -804,6 +802,7 @@ impl<T: Config> Pallet<T> {
|
||||
/// further.
|
||||
fn service_xcmp_queue(max_weight: Weight) -> Weight {
|
||||
let suspended = QueueSuspended::<T>::get();
|
||||
let mut messages_processed = 0;
|
||||
|
||||
let mut status = <InboundXcmpStatus<T>>::get(); // <- sorted.
|
||||
if status.is_empty() {
|
||||
@@ -832,12 +831,13 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
let mut shuffle_index = 0;
|
||||
while shuffle_index < shuffled.len() &&
|
||||
max_weight.saturating_sub(weight_used).all_gte(threshold_weight)
|
||||
max_weight.saturating_sub(weight_used).all_gte(threshold_weight) &&
|
||||
messages_processed < MAX_MESSAGES_PER_BLOCK
|
||||
{
|
||||
let index = shuffled[shuffle_index];
|
||||
let sender = status[index].sender;
|
||||
let sender_origin = T::ControllerOriginConverter::convert_origin(
|
||||
(1, Parachain(sender.into())),
|
||||
(Parent, Parachain(sender.into())),
|
||||
OriginKind::Superuser,
|
||||
);
|
||||
let is_controller = sender_origin
|
||||
@@ -872,6 +872,7 @@ impl<T: Config> Pallet<T> {
|
||||
let (weight_processed, is_empty) = Self::process_xcmp_message(
|
||||
sender,
|
||||
status[index].message_metadata[0],
|
||||
&mut messages_processed,
|
||||
weight_remaining,
|
||||
xcmp_max_individual_weight,
|
||||
);
|
||||
@@ -1133,28 +1134,60 @@ impl<T: Config> XcmpMessageSource for Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PriceForSiblingDelivery {
|
||||
fn price_for_sibling_delivery(id: ParaId, message: &Xcm<()>) -> MultiAssets;
|
||||
}
|
||||
|
||||
impl PriceForSiblingDelivery for () {
|
||||
fn price_for_sibling_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets {
|
||||
MultiAssets::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Get<MultiAssets>> PriceForSiblingDelivery for ConstantPrice<T> {
|
||||
fn price_for_sibling_delivery(_: ParaId, _: &Xcm<()>) -> MultiAssets {
|
||||
T::get()
|
||||
}
|
||||
}
|
||||
|
||||
/// Xcm sender for sending to a sibling parachain.
|
||||
impl<T: Config> SendXcm for Pallet<T> {
|
||||
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> Result<(), SendError> {
|
||||
let dest = dest.into();
|
||||
type Ticket = (ParaId, VersionedXcm<()>);
|
||||
|
||||
match &dest {
|
||||
fn validate(
|
||||
dest: &mut Option<MultiLocation>,
|
||||
msg: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<(ParaId, VersionedXcm<()>)> {
|
||||
let d = dest.take().ok_or(SendError::MissingArgument)?;
|
||||
|
||||
match &d {
|
||||
// An HRMP message for a sibling parachain.
|
||||
MultiLocation { parents: 1, interior: X1(Parachain(id)) } => {
|
||||
let versioned_xcm = T::VersionWrapper::wrap_version(&dest, msg)
|
||||
let xcm = msg.take().ok_or(SendError::MissingArgument)?;
|
||||
let id = ParaId::from(*id);
|
||||
let price = T::PriceForSiblingDelivery::price_for_sibling_delivery(id, &xcm);
|
||||
let versioned_xcm = T::VersionWrapper::wrap_version(&d, xcm)
|
||||
.map_err(|()| SendError::DestinationUnsupported)?;
|
||||
let hash = T::Hashing::hash_of(&versioned_xcm);
|
||||
Self::send_fragment(
|
||||
(*id).into(),
|
||||
XcmpMessageFormat::ConcatenatedVersionedXcm,
|
||||
versioned_xcm,
|
||||
)
|
||||
.map_err(|e| SendError::Transport(<&'static str>::from(e)))?;
|
||||
Self::deposit_event(Event::XcmpMessageSent { message_hash: Some(hash) });
|
||||
Ok(())
|
||||
Ok(((id, versioned_xcm), price))
|
||||
},
|
||||
// Anything else is unhandled. This includes a message this is meant for us.
|
||||
_ => Err(SendError::CannotReachDestination(dest, msg)),
|
||||
_ => {
|
||||
// Anything else is unhandled. This includes a message that is not meant for us.
|
||||
// We need to make sure that dest/msg is not consumed here.
|
||||
*dest = Some(d);
|
||||
Err(SendError::NotApplicable)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn deliver((id, xcm): (ParaId, VersionedXcm<()>)) -> Result<XcmHash, SendError> {
|
||||
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
|
||||
|
||||
match Self::send_fragment(id, XcmpMessageFormat::ConcatenatedVersionedXcm, xcm) {
|
||||
Ok(_) => {
|
||||
Self::deposit_event(Event::XcmpMessageSent { message_hash: Some(hash) });
|
||||
Ok(hash)
|
||||
},
|
||||
Err(e) => Err(SendError::Transport(<&'static str>::from(e))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ use frame_support::{
|
||||
traits::StorageVersion,
|
||||
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight},
|
||||
};
|
||||
use xcm::latest::Weight as XcmWeight;
|
||||
|
||||
/// The current storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
|
||||
@@ -33,8 +32,15 @@ pub fn migrate_to_latest<T: Config>() -> Weight {
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
|
||||
if StorageVersion::get::<Pallet<T>>() == 1 {
|
||||
weight += migrate_to_v2::<T>();
|
||||
weight.saturating_accrue(migrate_to_v2::<T>());
|
||||
StorageVersion::new(2).put::<Pallet<T>>();
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
}
|
||||
|
||||
if StorageVersion::get::<Pallet<T>>() == 2 {
|
||||
weight.saturating_accrue(migrate_to_v3::<T>());
|
||||
StorageVersion::new(3).put::<Pallet<T>>();
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
}
|
||||
|
||||
weight
|
||||
@@ -49,9 +55,9 @@ mod v1 {
|
||||
pub suspend_threshold: u32,
|
||||
pub drop_threshold: u32,
|
||||
pub resume_threshold: u32,
|
||||
pub threshold_weight: XcmWeight,
|
||||
pub weight_restrict_decay: XcmWeight,
|
||||
pub xcmp_max_individual_weight: XcmWeight,
|
||||
pub threshold_weight: u64,
|
||||
pub weight_restrict_decay: u64,
|
||||
pub xcmp_max_individual_weight: u64,
|
||||
}
|
||||
|
||||
impl Default for QueueConfigData {
|
||||
@@ -98,6 +104,12 @@ pub fn migrate_to_v2<T: Config>() -> Weight {
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
}
|
||||
|
||||
pub fn migrate_to_v3<T: Config>() -> Weight {
|
||||
let overweight_messages = <Pallet<T> as Store>::Overweight::initialize_counter() as u64;
|
||||
|
||||
T::DbWeight::get().reads_writes(overweight_messages, 1)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -18,7 +18,10 @@ use crate as xcmp_queue;
|
||||
use core::marker::PhantomData;
|
||||
use cumulus_pallet_parachain_system::AnyRelayNumber;
|
||||
use cumulus_primitives_core::{IsSystem, ParaId};
|
||||
use frame_support::{parameter_types, traits::OriginTrait};
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
traits::{Everything, Nothing, OriginTrait},
|
||||
};
|
||||
use frame_system::EnsureRoot;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
@@ -26,9 +29,7 @@ use sp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
};
|
||||
use xcm::prelude::*;
|
||||
use xcm_builder::{
|
||||
CurrencyAdapter, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsPreset,
|
||||
};
|
||||
use xcm_builder::{CurrencyAdapter, FixedWeightBounds, IsConcrete, NativeAsset, ParentIsPreset};
|
||||
use xcm_executor::traits::ConvertOrigin;
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
@@ -58,7 +59,7 @@ parameter_types! {
|
||||
type AccountId = u64;
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type BaseCallFilter = Everything;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
@@ -115,9 +116,10 @@ impl cumulus_pallet_parachain_system::Config for Test {
|
||||
|
||||
parameter_types! {
|
||||
pub const RelayChain: MultiLocation = MultiLocation::parent();
|
||||
pub Ancestry: MultiLocation = X1(Parachain(1u32.into())).into();
|
||||
pub UnitWeightCost: u64 = 1_000_000;
|
||||
pub UniversalLocation: InteriorMultiLocation = X1(Parachain(1u32.into())).into();
|
||||
pub UnitWeightCost: Weight = Weight::from_parts(1_000_000, 1024);
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
}
|
||||
|
||||
/// Means for transacting assets on this chain.
|
||||
@@ -145,7 +147,7 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type OriginConverter = ();
|
||||
type IsReserve = NativeAsset;
|
||||
type IsTeleporter = NativeAsset;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type UniversalLocation = UniversalLocation;
|
||||
type Barrier = ();
|
||||
type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
|
||||
type Trader = ();
|
||||
@@ -153,6 +155,15 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type AssetTrap = ();
|
||||
type AssetClaims = ();
|
||||
type SubscriptionService = ();
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type FeeManager = ();
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
type SafeCallFilter = Everything;
|
||||
}
|
||||
|
||||
pub type XcmRouter = (
|
||||
@@ -193,6 +204,7 @@ impl Config for Test {
|
||||
type ControllerOrigin = EnsureRoot<AccountId>;
|
||||
type ControllerOriginConverter = SystemParachainAsSuperuser<RuntimeOrigin>;
|
||||
type WeightInfo = ();
|
||||
type PriceForSiblingDelivery = ();
|
||||
}
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
|
||||
@@ -46,6 +46,7 @@ fn bad_message_is_handled() {
|
||||
XcmpQueue::process_xcmp_message(
|
||||
1000.into(),
|
||||
(1, format),
|
||||
&mut 0,
|
||||
Weight::from_ref_time(10_000_000_000),
|
||||
Weight::from_ref_time(10_000_000_000),
|
||||
);
|
||||
@@ -69,6 +70,7 @@ fn handle_blob_message() {
|
||||
XcmpQueue::process_xcmp_message(
|
||||
1000.into(),
|
||||
(1, format),
|
||||
&mut 0,
|
||||
Weight::from_ref_time(10_000_000_000),
|
||||
Weight::from_ref_time(10_000_000_000),
|
||||
);
|
||||
@@ -86,6 +88,7 @@ fn handle_invalid_data() {
|
||||
XcmpQueue::process_xcmp_message(
|
||||
1000.into(),
|
||||
(1, format),
|
||||
&mut 0,
|
||||
Weight::from_ref_time(10_000_000_000),
|
||||
Weight::from_ref_time(10_000_000_000),
|
||||
);
|
||||
@@ -96,7 +99,7 @@ fn handle_invalid_data() {
|
||||
fn service_overweight_unknown() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(
|
||||
XcmpQueue::service_overweight(RuntimeOrigin::root(), 0, 1000),
|
||||
XcmpQueue::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(1000, 1000)),
|
||||
Error::<Test>::BadOverweightIndex,
|
||||
);
|
||||
});
|
||||
@@ -109,7 +112,7 @@ fn service_overweight_bad_xcm_format() {
|
||||
Overweight::<Test>::insert(0, (ParaId::from(1000), 0, bad_xcm));
|
||||
|
||||
assert_noop!(
|
||||
XcmpQueue::service_overweight(RuntimeOrigin::root(), 0, 1000),
|
||||
XcmpQueue::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(1000, 1000)),
|
||||
Error::<Test>::BadXcm
|
||||
);
|
||||
});
|
||||
@@ -187,9 +190,15 @@ fn update_threshold_weight_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let data: QueueConfigData = <QueueConfig<Test>>::get();
|
||||
assert_eq!(data.threshold_weight, Weight::from_ref_time(100_000));
|
||||
assert_ok!(XcmpQueue::update_threshold_weight(RuntimeOrigin::root(), 10_000));
|
||||
assert_ok!(XcmpQueue::update_threshold_weight(
|
||||
RuntimeOrigin::root(),
|
||||
Weight::from_ref_time(10_000)
|
||||
));
|
||||
assert_noop!(
|
||||
XcmpQueue::update_threshold_weight(RuntimeOrigin::signed(5), 10_000_000),
|
||||
XcmpQueue::update_threshold_weight(
|
||||
RuntimeOrigin::signed(5),
|
||||
Weight::from_ref_time(10_000_000),
|
||||
),
|
||||
BadOrigin
|
||||
);
|
||||
let data: QueueConfigData = <QueueConfig<Test>>::get();
|
||||
@@ -203,9 +212,15 @@ fn update_weight_restrict_decay_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let data: QueueConfigData = <QueueConfig<Test>>::get();
|
||||
assert_eq!(data.weight_restrict_decay, Weight::from_ref_time(2));
|
||||
assert_ok!(XcmpQueue::update_weight_restrict_decay(RuntimeOrigin::root(), 5));
|
||||
assert_ok!(XcmpQueue::update_weight_restrict_decay(
|
||||
RuntimeOrigin::root(),
|
||||
Weight::from_ref_time(5)
|
||||
));
|
||||
assert_noop!(
|
||||
XcmpQueue::update_weight_restrict_decay(RuntimeOrigin::signed(6), 4),
|
||||
XcmpQueue::update_weight_restrict_decay(
|
||||
RuntimeOrigin::signed(6),
|
||||
Weight::from_ref_time(4),
|
||||
),
|
||||
BadOrigin
|
||||
);
|
||||
let data: QueueConfigData = <QueueConfig<Test>>::get();
|
||||
@@ -224,12 +239,12 @@ fn update_xcmp_max_individual_weight() {
|
||||
);
|
||||
assert_ok!(XcmpQueue::update_xcmp_max_individual_weight(
|
||||
RuntimeOrigin::root(),
|
||||
30u64 * WEIGHT_REF_TIME_PER_MILLIS
|
||||
Weight::from_ref_time(30u64 * WEIGHT_REF_TIME_PER_MILLIS)
|
||||
));
|
||||
assert_noop!(
|
||||
XcmpQueue::update_xcmp_max_individual_weight(
|
||||
RuntimeOrigin::signed(3),
|
||||
10u64 * WEIGHT_REF_TIME_PER_MILLIS
|
||||
Weight::from_ref_time(10u64 * WEIGHT_REF_TIME_PER_MILLIS)
|
||||
),
|
||||
BadOrigin
|
||||
);
|
||||
@@ -241,3 +256,88 @@ fn update_xcmp_max_individual_weight() {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Validates [`validate`] for required Some(destination) and Some(message)
|
||||
struct OkFixedXcmHashWithAssertingRequiredInputsSender;
|
||||
impl OkFixedXcmHashWithAssertingRequiredInputsSender {
|
||||
const FIXED_XCM_HASH: [u8; 32] = [9; 32];
|
||||
|
||||
fn fixed_delivery_asset() -> MultiAssets {
|
||||
MultiAssets::new()
|
||||
}
|
||||
|
||||
fn expected_delivery_result() -> Result<(XcmHash, MultiAssets), SendError> {
|
||||
Ok((Self::FIXED_XCM_HASH, Self::fixed_delivery_asset()))
|
||||
}
|
||||
}
|
||||
impl SendXcm for OkFixedXcmHashWithAssertingRequiredInputsSender {
|
||||
type Ticket = ();
|
||||
|
||||
fn validate(
|
||||
destination: &mut Option<MultiLocation>,
|
||||
message: &mut Option<Xcm<()>>,
|
||||
) -> SendResult<Self::Ticket> {
|
||||
assert!(destination.is_some());
|
||||
assert!(message.is_some());
|
||||
Ok(((), OkFixedXcmHashWithAssertingRequiredInputsSender::fixed_delivery_asset()))
|
||||
}
|
||||
|
||||
fn deliver(_: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||
Ok(Self::FIXED_XCM_HASH)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xcmp_queue_does_not_consume_dest_or_msg_on_not_applicable() {
|
||||
// dummy message
|
||||
let message = Xcm(vec![Trap(5)]);
|
||||
|
||||
// XcmpQueue - check dest is really not applicable
|
||||
let dest = (Parent, Parent, Parent);
|
||||
let mut dest_wrapper = Some(dest.clone().into());
|
||||
let mut msg_wrapper = Some(message.clone());
|
||||
assert_eq!(
|
||||
Err(SendError::NotApplicable),
|
||||
<XcmpQueue as SendXcm>::validate(&mut dest_wrapper, &mut msg_wrapper)
|
||||
);
|
||||
|
||||
// check wrapper were not consumed
|
||||
assert_eq!(Some(dest.clone().into()), dest_wrapper.take());
|
||||
assert_eq!(Some(message.clone()), msg_wrapper.take());
|
||||
|
||||
// another try with router chain with asserting sender
|
||||
assert_eq!(
|
||||
OkFixedXcmHashWithAssertingRequiredInputsSender::expected_delivery_result(),
|
||||
send_xcm::<(XcmpQueue, OkFixedXcmHashWithAssertingRequiredInputsSender)>(
|
||||
dest.into(),
|
||||
message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xcmp_queue_consumes_dest_and_msg_on_ok_validate() {
|
||||
// dummy message
|
||||
let message = Xcm(vec![Trap(5)]);
|
||||
|
||||
// XcmpQueue - check dest/msg is valid
|
||||
let dest = (Parent, X1(Parachain(5555)));
|
||||
let mut dest_wrapper = Some(dest.clone().into());
|
||||
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(|| {
|
||||
// another try with router chain with asserting sender
|
||||
assert_eq!(
|
||||
Err(SendError::Transport("NoChannel")),
|
||||
send_xcm::<(XcmpQueue, OkFixedXcmHashWithAssertingRequiredInputsSender)>(
|
||||
dest.into(),
|
||||
message
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user