Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Companion for polkadot#7234 (XCM: Tools for uniquely referencing mess…
Browse files Browse the repository at this point in the history
…ages) (#2601)

* Fixes for new API

* Formatting

* Fixes

* Fixes

* Further fixes

* XCMP dispatch events mention message ID

* XCMP event includes ID

* Add DMP message ID functionality

* Integrate into test parachains

* Remove WithUniqueTopic usage

* Use new primitive

* Formatting

* undiener

* Revert lock

* Fixes

* Fixes

* Fixes

* Fixes

* Formatting

* message_hash becomes message_id

* Rename

* Another Rename

* Fixes

* Fix

* Bump

* Fixes

* Grumble.
  • Loading branch information
gavofyork authored May 25, 2023
1 parent e9bfaa9 commit 10afc2f
Show file tree
Hide file tree
Showing 23 changed files with 432 additions and 570 deletions.
135 changes: 68 additions & 67 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ opt-level = 3
inherits = "release"
lto = true
codegen-units = 1

168 changes: 81 additions & 87 deletions pallets/dmp-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub struct PageIndexData {

/// Simple type used to identify messages for the purpose of reporting events. Secure if and only
/// if the message content is unique.
pub type MessageId = [u8; 32];
pub type MessageId = XcmHash;

/// Index used to identify overweight messages.
pub type OverweightIndex = u64;
Expand Down Expand Up @@ -174,23 +174,39 @@ pub mod pallet {
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// Downward message is invalid XCM.
InvalidFormat { message_id: MessageId },
InvalidFormat { message_hash: XcmHash },
/// Downward message is unsupported version of XCM.
UnsupportedVersion { message_id: MessageId },
UnsupportedVersion { message_hash: XcmHash },
/// Downward message executed with the given outcome.
ExecutedDownward { message_id: MessageId, outcome: Outcome },
ExecutedDownward { message_hash: XcmHash, message_id: XcmHash, outcome: Outcome },
/// The weight limit for handling downward messages was reached.
WeightExhausted { message_id: MessageId, remaining_weight: Weight, required_weight: Weight },
WeightExhausted {
message_hash: XcmHash,
message_id: XcmHash,
remaining_weight: Weight,
required_weight: Weight,
},
/// Downward message is overweight and was placed in the overweight queue.
OverweightEnqueued {
message_id: MessageId,
message_hash: XcmHash,
message_id: XcmHash,
overweight_index: OverweightIndex,
required_weight: Weight,
},
/// Downward message from the overweight queue was executed.
OverweightServiced { overweight_index: OverweightIndex, weight_used: Weight },
/// The maximum number of downward messages was.
MaxMessagesExhausted { message_id: MessageId },
/// The maximum number of downward messages was reached.
MaxMessagesExhausted { message_hash: XcmHash },
}

/// Error type when a message was failed to be serviced.
pub(crate) struct ServiceMessageError {
/// The message's hash.
message_hash: XcmHash,
/// The message's ID (which could also be its hash if nothing overrides it).
message_id: XcmHash,
/// Weight required for the message to be executed.
required_weight: Weight,
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -250,30 +266,41 @@ pub mod pallet {
limit: Weight,
_sent_at: RelayBlockNumber,
mut data: &[u8],
) -> Result<Weight, (MessageId, Weight)> {
let message_id = sp_io::hashing::blake2_256(data);
) -> Result<Weight, ServiceMessageError> {
let message_hash = sp_io::hashing::blake2_256(data);
let mut message_id = message_hash;
let maybe_msg = VersionedXcm::<T::RuntimeCall>::decode_all_with_depth_limit(
MAX_XCM_DECODE_DEPTH,
&mut data,
)
.map(Xcm::<T::RuntimeCall>::try_from);
match maybe_msg {
Err(_) => {
Self::deposit_event(Event::InvalidFormat { message_id });
Self::deposit_event(Event::InvalidFormat { message_hash });
Ok(Weight::zero())
},
Ok(Err(())) => {
Self::deposit_event(Event::UnsupportedVersion { message_id });
Self::deposit_event(Event::UnsupportedVersion { message_hash });
Ok(Weight::zero())
},
Ok(Ok(x)) => {
let outcome = T::XcmExecutor::execute_xcm(Parent, x, message_id, limit);
let outcome = T::XcmExecutor::prepare_and_execute(
Parent,
x,
&mut message_id,
limit,
Weight::zero(),
);
match outcome {
Outcome::Error(XcmError::WeightLimitReached(required)) =>
Err((message_id, required)),
Outcome::Error(XcmError::WeightLimitReached(required_weight)) =>
Err(ServiceMessageError { message_hash, message_id, required_weight }),
outcome => {
let weight_used = outcome.weight_used();
Self::deposit_event(Event::ExecutedDownward { message_id, outcome });
Self::deposit_event(Event::ExecutedDownward {
message_hash,
message_id,
outcome,
});
Ok(weight_used)
},
}
Expand Down Expand Up @@ -314,15 +341,19 @@ pub mod pallet {
maybe_enqueue_page = Some(Vec::with_capacity(item_count_left));

Self::deposit_event(Event::MaxMessagesExhausted {
message_id: sp_io::hashing::blake2_256(&data),
message_hash: sp_io::hashing::blake2_256(&data),
});
} else {
// 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)) =>
Err(ServiceMessageError {
message_hash,
message_id,
required_weight,
}) =>
// Too much weight required right now.
{
let is_under_limit =
Expand All @@ -334,6 +365,7 @@ pub mod pallet {
let overweight_index = page_index.overweight_count;
Overweight::<T>::insert(overweight_index, (sent_at, data));
Self::deposit_event(Event::OverweightEnqueued {
message_hash,
message_id,
overweight_index,
required_weight,
Expand All @@ -348,6 +380,7 @@ pub mod pallet {
let item_count_left = item_count.saturating_sub(i);
maybe_enqueue_page = Some(Vec::with_capacity(item_count_left));
Self::deposit_event(Event::WeightExhausted {
message_hash,
message_id,
remaining_weight,
required_weight,
Expand Down Expand Up @@ -466,50 +499,36 @@ mod tests {
})
}

pub enum Weightless {}
impl PreparedMessage for Weightless {
pub struct MockPrepared(Xcm);
impl PreparedMessage for MockPrepared {
fn weight_of(&self) -> Weight {
unreachable!()
match ((self.0).0.len(), &(self.0).0.first()) {
(1, Some(Transact { require_weight_at_most, .. })) => *require_weight_at_most,
_ => Weight::from_parts(1, 1),
}
}
}

pub struct MockExec;
impl ExecuteXcm<RuntimeCall> for MockExec {
type Prepared = Weightless;
type Prepared = MockPrepared;

fn prepare(_message: Xcm) -> Result<Self::Prepared, Xcm> {
unreachable!()
fn prepare(message: Xcm) -> Result<Self::Prepared, Xcm> {
Ok(MockPrepared(message))
}

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,
_hash: XcmHash,
weight_limit: Weight,
prepared: MockPrepared,
_id: &mut XcmHash,
_weight_credit: Weight,
) -> Outcome {
let message = prepared.0;
let o = match (message.0.len(), &message.0.first()) {
(1, Some(Transact { require_weight_at_most, .. })) => {
if require_weight_at_most.all_lte(weight_limit) {
Outcome::Complete(*require_weight_at_most)
} else {
Outcome::Error(XcmError::WeightLimitReached(*require_weight_at_most))
}
},
(1, Some(Transact { require_weight_at_most, .. })) =>
Outcome::Complete(*require_weight_at_most),
// use 1000 to decide that it's not supported.
_ => Outcome::Incomplete(
Weight::from_parts(1000, 1000).min(weight_limit),
XcmError::Unimplemented,
),
_ => Outcome::Incomplete(Weight::from_parts(1, 1), XcmError::Unimplemented),
};
TRACE.with(|q| q.borrow_mut().push((message, o.clone())));
o
Expand Down Expand Up @@ -564,13 +583,6 @@ mod tests {
(msg(weight), Outcome::Complete(Weight::from_parts(weight, weight)))
}

fn msg_limit_reached(weight: u64) -> (Xcm, Outcome) {
(
msg(weight),
Outcome::Error(XcmError::WeightLimitReached(Weight::from_parts(weight, weight))),
)
}

fn pages_queued() -> PageCounter {
PageIndex::<Test>::get().end_used - PageIndex::<Test>::get().begin_used
}
Expand Down Expand Up @@ -613,10 +625,7 @@ mod tests {
enqueue(&enqueued);
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),]
);
assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001),]);
});
}

Expand All @@ -631,18 +640,15 @@ mod tests {
PageIndexData { begin_used: 0, end_used: 1, overweight_count: 0 }
);
assert_eq!(Pages::<Test>::get(0).len(), 3);
assert_eq!(take_trace(), vec![msg_limit_reached(1000)]);
assert_eq!(take_trace(), vec![]);

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),]
);
assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001)]);

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_eq!(take_trace(), vec![msg_complete(1002)]);
assert!(queue_is_empty());
});
}
Expand All @@ -655,7 +661,7 @@ mod tests {
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),]);
assert_eq!(take_trace(), vec![msg_complete(1000)]);

let weight_used = handle_messages(&[], Weight::from_parts(2500, 2500));
assert_eq!(weight_used, Weight::from_parts(2003, 2003));
Expand Down Expand Up @@ -693,13 +699,13 @@ mod tests {
enqueue(&enqueued);
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!(take_trace(), vec![msg_complete(1000)]);
assert_eq!(pages_queued(), 2);

// 5000 is not enough to process the 10001 blocker, so nothing happens.
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),]);
assert_eq!(take_trace(), vec![]);

// 20000 is now enough to process everything.
let weight_used = handle_messages(&[], Weight::from_parts(20000, 20000));
Expand All @@ -720,10 +726,7 @@ mod tests {
enqueue(&enqueued);
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),]
);
assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1001)]);
assert_eq!(pages_queued(), 1);

// 20000 is now enough to process everything.
Expand All @@ -744,12 +747,7 @@ mod tests {
assert_eq!(weight_used, Weight::from_parts(3003, 3003));
assert_eq!(
take_trace(),
vec![
msg_complete(1000),
msg_complete(1001),
msg_complete(1002),
msg_limit_reached(10003),
]
vec![msg_complete(1000), msg_complete(1001), msg_complete(1002),]
);
assert_eq!(pages_queued(), 1);

Expand All @@ -768,19 +766,19 @@ mod tests {
enqueue(&enqueued);
let weight_used = handle_messages(&[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!(take_trace(), vec![msg_complete(1000)]);
assert_eq!(pages_queued(), 2);
assert_eq!(PageIndex::<Test>::get().begin_used, 0);

let weight_used = handle_messages(&[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!(take_trace(), vec![msg_complete(1001)]);
assert_eq!(pages_queued(), 2);
assert_eq!(PageIndex::<Test>::get().begin_used, 1);

let weight_used = handle_messages(&[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!(take_trace(), vec![msg_complete(1002)]);
assert_eq!(pages_queued(), 2);
assert_eq!(PageIndex::<Test>::get().begin_used, 2);
});
Expand All @@ -798,10 +796,7 @@ mod tests {
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(),
vec![msg_complete(1000), msg_limit_reached(10001), msg_complete(1002),]
);
assert_eq!(take_trace(), vec![msg_complete(1000), msg_complete(1002),]);

assert_eq!(overweights(), vec![0]);
});
Expand All @@ -818,7 +813,7 @@ mod tests {
let incoming = vec![msg(10000)];
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!(take_trace(), vec![]);
assert_eq!(overweights(), vec![0]);

assert_noop!(
Expand All @@ -845,7 +840,7 @@ mod tests {
),
Error::<Test>::OverLimit
);
assert_eq!(take_trace(), vec![msg_limit_reached(10000)]);
assert_eq!(take_trace(), vec![]);

let base_weight =
super::Call::<Test>::service_overweight { index: 0, weight_limit: Weight::zero() }
Expand Down Expand Up @@ -891,7 +886,6 @@ mod tests {
msg_complete(1002),
msg_complete(1003),
msg_complete(1004),
msg_limit_reached(1005),
]
);
assert_eq!(pages_queued(), 1);
Expand Down
Loading

0 comments on commit 10afc2f

Please sign in to comment.